Что лучше в отношении времени и пространства: фильтр Блума, хэш-таблица или словарь? - PullRequest
11 голосов
/ 11 января 2011

Мне нужно хранить 4000 строк фиксированного размера (8 символов) в C #, но я не знаю Что лучше всего использовать в отношении места и времени добавления и получения элемента: фильтр Блума, хэш-таблица или словарь? Пожалуйста, если кто-нибудь может мне помочь

Ответы [ 3 ]

31 голосов
/ 11 января 2011

В этом вопросе у вас есть только две структуры данных в C #, так как словари в C # реализованы с использованием хеш-таблиц.Поэтому мы будем ссылаться на Dictionary и HashTable как на хеш-таблицы.Если вы используете один из них, то, вероятно, вам нужен словарь из-за безопасности типов и производительности, как описано здесь: Почему словарь предпочтительнее хеш-таблицы? Но так как словарь реализован с использованием хеш-таблицы, он не является огромнымразница в любом случае.

Но реальный вопрос - хеш-таблица (словарь) против фильтра Блума.Кто-то ранее задавал связанный вопрос: В чем преимущество использования фильтров Блума? Они также ссылаются на страницу Википедии по фильтрам Блума, которая является довольно информативной: https://en.wikipedia.org/wiki/Bloom_filter Короткие версииОтвет в том, что фильтры Блума меньше и быстрее.Однако у них есть стоимость, связанная с этим: они не совсем точны.В хэш-таблице исходная строка всегда сохраняется для точного сравнения.Сначала вы хэшируете значение, и это говорит вам, где в таблице искать.После того, как вы посмотрели в таблице, вы сравниваете расположенное там значение со значением, которое вы ищете.В фильтре Блума вы используете несколько хешей для вычисления набора местоположений.Если во всех этих местах есть единицы, то вы считаете, что строка найдена.Это означает, что иногда будут «найдены» строки, которые изначально не были вставлены.Если таблица слишком мала, на самом деле вы можете достичь точки насыщения, где может показаться, что любая строка, которую вы пробовали, будет в фильтре Блума.Поскольку вы знаете, сколько строк вы собираетесь вставить, вы можете соответствующим образом изменить размер таблицы.

Давайте рассмотрим соответствующие размеры.Чтобы цифры были четкими, я сделаю вид, что у вас ровно 4096 строк.Чтобы иметь относительно низкую коллизию хеш-таблицы, вы бы хотели, чтобы ваша таблица была как минимум такой же, как количество строк.Таким образом, реалистично (при условии 32-битных (4-байтовых) указателей), в этом случае вы бы смотрели размер таблицы 4096 * 4 байта = 16 КБ, плюс 4096 * (4 + 4 + 8) = 64 КБ для таблицы.узлы списка (следующий указатель + указатель строки) и строки.Таким образом, в общей сложности, вероятно, около 80 КБ, что, вероятно, не очень много памяти в большинстве ситуаций, когда вы будете использовать C #.

Для фильтров Блума мы должны решить, какую частоту ошибок мы хотим достичь внаши расчеты размера.Когда мы говорим о частоте ошибок 1%, это будет означать, что из каждых 100 строк, которые не были вставлены в фильтр Блума, 1 будет ошибочно указано как присутствующее.Вставленные строки всегда будут правильно обозначены как вставленные.Используя уравнение m = -n * ln (p) / (ln (2) ^ 2), мы можем вычислить минимальный размер, чтобы дать нам определенный коэффициент ошибок.В этом уравнении m - это количество слотов в таблице, p - частота ошибок, а n - количество вставляемых строк.Итак, если мы установим p равным 0,01 (ошибка 1%), то получим примерно 9,6 * 4096 бит = 9,6 * 512 байт = 4,8 КБ, что, очевидно, немного меньше.Но, на самом деле, 1% является чем-то высоким для уровня ошибок.Более того, на самом деле, мы, вероятно, должны пойти на что-то более 0,0001%, что составляет 28,8 * 4096b бит = 28,8 * 512 байт = 14,4 КБ.Очевидно, что любой из них существенно меньше, чем 80К, которые мы рассчитали для хеш-таблицы.Тем не менее, хэш-таблица имеет уровень ошибок 0, который явно меньше 1% или 0,0001%.

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

3 голосов
/ 11 января 2011

A словарь - это абстрактный тип данных, который представляет отображение из одного типа в другой. Он не определяет, какова реализация словаря - он может быть поддержан хеш-таблицей, сбалансированным бинарным деревом поиска, списком пропусков или одной из многих других структур. Это, вероятно, не подходит здесь, потому что словарь связывает один тип элементов с другим типом. Вы этого не делаете - вы просто озабочены хранением элементов - так что это, вероятно, неуместно.

A Фильтр Блума - это вероятностная структура данных, которая хороша для проверки того, является ли элемент определенно не в наборе, но не может точно сказать, что-то это в наборе. Он обычно используется в распределенных системах, чтобы избежать ненужных сетевых чтений. Каждый компьютер может хранить фильтр Блума о том, какие записи могут находиться в базе данных, и может отфильтровывать заведомо ненужные сетевые вызовы, не запрашивая удаленную систему, если запись исключается фильтром. Это не очень хорошо для того, что вы пытаетесь сделать, поскольку ложные срабатывания, вероятно, нарушают условия сделки.

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

Если вы хотите отсортированный порядок, есть две другие структуры, которые вы можете рассмотреть. Первым будет сбалансированное двоичное дерево поиска 1018 *, которое поддерживает быстрый поиск и удаление и сохраняет элементы в отсортированном порядке. Есть много хороших реализаций там; практически все хорошие языки программирования поставляются с реализацией. Другой - trie , который поддерживает очень быстрый поиск и доступ и поддерживает отсортированный порядок. Это может быть немного неэффективно в зависимости от распределения ваших строк, но может быть именно тем, что вы ищете.

Надеюсь, это поможет!

1 голос
/ 11 января 2011

System.Collections.Hashtable в .NET 1.0 на самом деле точно такой же, как System.Collections.Generic.Dictionary, который он представлен в .NET 2.0.

Я бы предложил вам использовать словарьтак как это безопасный тип, указав ваш ключ и тип значения.Hashtable принимает только тип объекта, вам придется приводить его обратно к строке каждый раз, когда вы получаете данные.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...