В целом, существует несколько вариантов того, как хеш-таблицы обрабатывают переполнение.
Многие (включая Java, если память служит) изменяют размер, когда коэффициент загрузки (процент используемых корзин) превышает определенный процент,Недостатком этого является то, что скорость является ненадежной - большинство вставок будет O (1), но некоторые будут O (N).
Чтобы смягчить эту проблему, некоторые вместо этого постепенно изменяют размер: когда нагрузкакоэффициент превышает магическое число, они:
- Создать вторую (большую) хеш-таблицу.
- Вставьте новый элемент в новую хеш-таблицу.
- Переместите немногоэлементы из существующей хеш-таблицы в новую.
Затем каждая последующая вставка перемещает другой кусок из старой хеш-таблицы в новую.Это сохраняет O (1) среднюю сложность и может быть записано так, чтобы сложность для каждой вставки была практически постоянной: когда хеш-таблица становится «полной» (т. Е. Коэффициент загрузки превышает вашу точку запуска), вы удваиваете размер таблицы.Затем в каждую вставку вы вставляете новый элемент и перемещаете один элемент из старой таблицы в новую.Старая таблица будет очищаться в точности по мере заполнения новой, поэтому каждая вставка будет включать в себя ровно две операции: вставка одного нового элемента и перемещение одного старого, поэтому скорость вставки остается практически постоянной.
Есть и другие стратегии.Одна из них, которая мне особенно нравится - это сделать хеш-таблицу таблицей сбалансированных деревьев.При этом вы обычно полностью игнорируете переполнение.Когда хеш-таблица заполняется, вы просто получаете больше элементов в каждом дереве.Теоретически это означает, что сложность равна O (log N), но для любого практического размера она пропорциональна log N/M
, где M = количество сегментов.Для практических диапазонов размеров (например, до нескольких миллиардов элементов) это по существу постоянно (log N
растет очень медленно), и это часто немного быстрее для самой большой таблицы, которую вы можете поместить в память, и потерянбыстрее для меньших размеров.Недостатком является то, что это действительно практично, когда объекты, которые вы храните, достаточно велики - если вы сохраняете (например) один символ на узел, накладные расходы от двух указателей (плюс, как правило, информация о балансе) на узел будут чрезвычайновысокий.