Можно ли ускорить хэш-таблицу, используя двоичные деревья поиска для раздельного связывания?

11

Я хочу реализовать хеш-таблицу с использованием деревьев двоичного поиска, чтобы уменьшить сложность поиска в процессе раздельного связывания с O (n) (используя связанный список) до O (log n) (используя BST). Можно ли это сделать, и если да, то как? Было бы легче понять, если решение шаг за шагом, реализация логики.

Я хочу сократить время поиска в хеш-таблице (сборка с использованием отдельной цепочки), но в то же время я не хочу увеличивать время вставки. Для моего проекта я не могу изменить хэш-функцию, чтобы уменьшить коллизии. Но из-за масштабируемости происходят столкновения. Я пытаюсь найти обходной путь, чтобы я мог как-то работать с лучшим доступом и вставить время в случае коллизии ... то есть управлять текущим состоянием, а не реструктурировать весь алгоритм. Если не получится, придется реструктурировать. Так есть идеи?

Aviral
источник
4
Хеш-таблицы и деревья двоичного поиска - это разные контейнеры. Таким образом, вы не можете делать то, что вы предлагаете (или вы делаете терминологическую ошибку).
Василий Старынкевич
Я думаю, вы могли бы поместить пару хэш / значение в каждый узел дерева ... но это будет либо плохая хеш-таблица, либо плохое двоичное дерево. Без какого-либо разъяснения, почему вы хотите сделать это вообще и на что вы хотите, чтобы конечный результат был способен, я не уверен, что это действительно ответственно.
Ixrec
1
@AK_: Да, что-то в этом роде, как вы сказали. Я хочу обрабатывать столкновения, используя двоичное дерево поиска. Я немного исправил свой вопрос, чтобы прояснить его.
Aviral
1
Обратите внимание, что тогда идет штраф O (n log n) за каждую вставку. В общем, когда у вас есть хеш-таблица, которая начинает заполняться (а цепочки длиннее, чем вы можете терпеть), вы перестраиваете хеш. Если вы регулярно сталкиваетесь с цепями длиннее 3 или 4, что-то не так.
3
Существует множество вариаций в хэш-таблице для уменьшения коллизий, открытой адресации и динамического изменения размера таблицы. Какой из них соответствует вашим требованиям - это то, что вам нужно изучить. Ваш текущий подход

Ответы:

11

То, что вы просите, возможно, учитывая ваши ограничения.

Анализ

Сильной стороной хеш-таблицы является ее быстрый поиск и скорость вставки. Чтобы получить эту скорость, нужно оставить любое подобие порядка в таблице: то есть все записи перемешаны. Список приемлем для использования в качестве записи таблицы, потому что, хотя обход равен O (n), списки имеют тенденцию быть короткими, если хеш-таблица достаточно велика, а объекты, хранящиеся в таблице, хешируются с использованием алгоритма хеширования хорошего качества.

Бинарное дерево поиска (BST) имеет быструю вставку и поиск в O (log 2 n). Это также накладывает ограничение на элементы, которые он хранит: должен быть какой-то способ упорядочить элементы. Учитывая два элемента A и B, хранящихся в дереве, должна быть возможность определить, предшествует ли A B или имеют ли они эквивалентный порядок.

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

Если у ваших элементов хеш-таблицы есть порядок, то вы можете использовать BST в качестве записи хеш-таблицы для хранения объектов с одинаковым хеш-кодом (коллизиями). Однако из-за того, что BST имеет O (log 2 n) поиск и вставку, это означает, что наихудший случай для всей структуры (хеш-таблица плюс BST) технически лучше, чем использование списка в качестве записи таблицы. В зависимости от реализации BST потребуется больше памяти, чем список, но, вероятно, не намного больше.

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

Реализация

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

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

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


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

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

Уолтер Брайт наиболее известен как изобретатель языка программирования D , но также написал вариант ECMAScript под названием DMDScript . В прошлом заголовок DMDScript (или, возможно, предка - кажется, я помню имя DScript) гласил, что его хеш-таблицы имеют тенденцию превосходить таковые во многих похожих языках. Причина - обработка столкновений с использованием бинарных деревьев.

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

Steve314
источник