C # Двоичные деревья и словари

голоса
15

Я изо всех сил с концепцией, когда использовать бинарные деревья поиска и когда использовать словари.

В моем приложении я сделал небольшой эксперимент , который использовал библиотеку C5 TreeDictionary(который я считаю , это красно-черным дерево двоичного поиска), и C # словарь. Словарь всегда быстрее был добавить / найти работу , а также всегда используется меньший объем памяти. Например, в 16809 <int, float>записей, словарь используется 342 KiB в то время как дерево используется 723 KiB.

Я думал, что BST-х должны были быть меньше памяти, но, кажется, что один узел дерева требует больше байт, чем одна запись в словаре. Что дает? Есть точка, в которой BST-х лучше, чем словари?

Кроме того , в качестве побочного вопроса, кто - нибудь знает , если есть быстрее + больше памяти эффективной структуры данных для хранения <int, float>пар для словаря типа доступа , чем любые из упомянутых структур?

Задан 28/01/2010 в 02:46
источник пользователем
На других языках...                            


6 ответов

голоса
1

Мне кажется, что вы делаете преждевременную оптимизацию.

То, что я хотел бы предложить вам, чтобы создать интерфейс для изоляции, в состав которого на самом деле вы используете, а затем реализует интерфейс, используя словарь (который, кажется, работает лучше всего).

Если память / производительность становится проблема (что, вероятно, не для 20k- чисел), то вы можете создать другие реализации интерфейса, и проверить, какие из них работают рекорды. Вам не нужно будет менять почти все в остальной части кода (за исключением, реализация которых вы используете).

Ответил 28/01/2010 в 03:26
источник пользователем

голоса
1

Это имеет смысл , что узел дерева будет требовать больше памяти , чем словарная статья. Двоичный узел дерева должен хранить значение и обе левые и правые поддеревья. Родовое Dictionary<TKey, TValue>реализован в виде хэш - таблицы, - я предполагаю - либо использует связанный список для каждого сегмента (значение плюс один указатель / ссылка) или какой - то переназначения (только значение). Я должен был бы иметь заглянуть в отражатель , чтобы быть уверенным, но для целей данного вопроса я не думаю , что это так важно.

Скудной хэш-таблица, тем менее эффективна с точки зрения хранения / памяти. Если создать хэш-таблицу (словарь) и инициализировать его мощность до 1 миллиона, и только заполнить его с 10000 элементов, то я уверен, что он будет съедать намного больше памяти, чем BST с 10000 узлов.

Тем не менее, я бы не беспокоиться об этом, если количество узлов / ключей только в тысячах. Это собирается быть измерена в килобайтах, по сравнению с гигабайтами оперативной памяти.


Если вопрос «почему вы хотите использовать бинарное дерево вместо хэш-таблицы?» Тогда лучший ответ ИМО, что бинарные деревья упорядочены, тогда как хэш-таблицы не являются. Вы можете осуществить поиск только хэш-таблицу для ключей, которые точно равны к чему-то; с деревом, вы можете найти диапазон значений, ближайшее значение, и т.д. Это очень важное различие, если вы создаете индекс или что-то подобное.

Ответил 28/01/2010 в 03:39
источник пользователем

голоса
0

Интерфейс для дерева и хэш-таблицы (который я предполагаю, что ваш словарь основан один) должен быть очень похожи. Всегда вращается вокруг в привязке поиск.

Я всегда думал, словарь лучше для создания вещей один раз и затем затем делать много поисков на нем. В то время как дерево было лучше, если бы вы были его модификации значительно. Тем не менее, я не знаю, где я взял эту идею вверх от.

(Функциональные языки часто используют деревья в качестве основы для них коллекций, как вы можете повторно использовать большую часть дерева, если вы сделаете небольшие изменения к нему).

Ответил 28/01/2010 в 03:40
источник пользователем

голоса
0

Вы не сравнивая «яблоки с яблоками», BST даст вам заказанное представление в то время как словарь позволяет сделать поиск по ключевой паре значений (в вашем случае).

Я бы не ожидал большого размера в памяти след между 2, но словарь даст вам гораздо быстрее поиска. Чтобы найти элемент в BST вы (потенциально) необходимо пройти по всему дереву. Но сделать dictnary поиск просто поиск на основе ключа.

Ответил 28/01/2010 в 04:05
источник пользователем

голоса
8

Я думал, что BST-х должны были быть меньше памяти, но, кажется, что один узел дерева требует больше байт, чем одна запись в словаре. Что дает? Есть точка, в которой BST-х лучше, чем словари?

Я лично никогда не слышал о таком принципе. Даже до сих пор, его единственный общий принцип, а не категорический факт травлению в ткани Вселенной.

Как правило, словари действительно просто фантазии обертка вокруг массива связанных списков. Вы вставляете в словаре что-то вроде:

LinkedList<Tuple<TKey, TValue>> list =
    internalArray[internalArray % key.GetHashCode()];
if (list.Exists(x => x.Key == key))
    throw new Exception("Key already exists");
list.AddLast(Tuple.Create(key, value));

Таким образом , ее почти O (1) операция. Словарь использует O (internalArray.Length + N) памяти, где п количество элементов в коллекции.

В целом BSTs могут быть реализованы в виде:

  • связанные-листы, которые используют O (N) пространства, где п элементы числа в коллекции.
  • массивы , которые используют O (2 ч - п) пространство , где Н представляет собой высоту дерева и п является количество элементов в коллекции.
    • Так как красно-черные дерева имеют ограниченную высоту O (1,44 * п), реализация массива должна иметь ограниченное использование памяти о O (2 1.44n - н)

Разногласия, С5 TreeDictionary осуществляется с использованием массивов, которые, вероятно, отвечает за неиспользуемое пространство.

Что дает? Есть точка, в которой BST-х лучше, чем словари?

Словари имеют некоторые нежелательные свойства:

  • Там не может быть достаточно continugous блоков памяти для хранения вашего словаря, даже если его требование к памяти намного меньше, чем в общей доступной памяти.

  • Оценка хэш - функции может принимать сколь угодно долго отрезок времени. Струны, например, использовать отражатель , чтобы изучить System.String.GetHashCodeметод - вы заметите хэширование строки всегда занимает O (N) время, что означает , что он может занять значительное время для очень длинных строк. На руке, сравнения строк для неравенства почти всегда быстрее хеширования, так как он может потребовать , глядя на только первые несколько символов. Его вполне возможно для дерева вставки , чтобы быть быстрее , чем словарных вставки , если вычисление хэш - код занимает слишком много времени.

    • Int32 в GetHashCodeметод буквально return this, так что вы бы hardpressed найти случай , когда Хеш с ИНТ ключами происходит медленнее , чем в словаре дерева.

RB Деревья имеют некоторые желательные свойства:

  • Вы можете найти / удалить элементы и Min Max в O (журнал п), по сравнению с O (N) времени, используя словарь.

  • Если дерево реализовано в виде связанного списка , а не массив, дерево , как правило , более эффективно , чем пространство словаря.

  • Кроме того, его смешно легко писать неизменные версии деревьев , которые поддерживают вставки / поиск / удаление в O (журнал п). Словари не очень хорошо адаптироваться к неизменности, так как вам необходимо скопировать весь внутренний массив для каждой операции ( на самом деле, я уже видел несколько массивов на основе реализаций неизменных пальцев деревьев, вид общего назначения словаря структуры данных, но реализация очень сложный).

  • Вы можете пройти все элементы дерева в отсортированном порядке в постоянном пространстве и O (N) времени, в то время как вам нужно сбросить хэш-таблицу в массив и сортировать его, чтобы получить тот же эффект.

Таким образом, выбор структуры данных действительно зависит от того, какие свойства вам нужно. Если вы просто хотите неупорядоченную сумку и можете гарантировать, что ваш хэш-функция оценку быстро, идти с .Net словарем. Если вам нужен упорядоченный мешок или имеет медленную функцию работает хэш, идти с TreeDictionary.

Ответил 28/01/2010 в 04:16
источник пользователем

голоса
0

СБАЛАНСИРОВАННЫЙ BST является предпочтительным, если вам нужно, чтобы защитить вашу структуру данных от латентности пиков и хэша столкновений атак.

Бывший случается, когда массив спинок структура растет получает изменена, последний является неизбежным свойством алгоритма хеширования в качестве проекции из бесконечного пространства в ограниченный диапазон целого.

Еще одна проблема в .NET является то, что есть ЛОХ, и с достаточно большим словарем вы столкнетесь фрагментации LOH. В этом случае вы можете использовать BST, расплачивается большим алгоритмического класс сложности.

Короче говоря, с BST при поддержке кучи распределения вы получите худший случай O (журнал (N)) время, с Хеш вы получите O (N) в худшем случае.

BST поставляется по цене O (журнал (N)) среднего времени, хуже кэш местности и больше ассигнований кучи, но у него есть латентные гарантии и защита от атак по словарю и фрагментации памяти.

Стоит отметить, что БСТ также подвержены фрагментации памяти на других платформах, а не с помощью уплотн сборщика мусора.

Что касается размера памяти, класс .NET Dictionary`2 больше памятей эффективных, поскольку он хранит данные в виде не совсем куч связанного списка, значение, которое хранит только и информации смещения. ЛУЧШИЙ должен хранить заголовок объекта (так как каждый узел представляет собой экземпляр класса в куче), два указателя, и некоторые данные дополненной дерево для сбалансированных деревьев. Например, красно-черное дерево нужно будет логическое значение интерпретируется как цвет (красный или черный). Это, по крайней мере, 6 машинных слов, если я не ошибаюсь. Таким образом, каждый узел красно-черного дерева на 64-битной системе составляет минимум:

3 слова для заголовка = 24 байта 2 слова для ребенка указателей = 16 байтов 1 слово для цвета = 8 байт, по крайней мере 1 слово для значения 8+ байт = 24 + 16 + 8 + 8 = 56 байт (+8 байтов если дерево использует указатель родительского узла).

В то же время, минимальный размер словарного будет всего 16 байт.

Ответил 10/12/2018 в 13:18
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more