This commit is contained in:
krahets
2026-04-14 18:06:19 +08:00
parent 17b2a0b630
commit cf0747ba3e
131 changed files with 604 additions and 609 deletions
+3 -3
View File
@@ -4362,7 +4362,7 @@
<li>Передав <code>key</code> , мы можем получить <code>value</code> из хеш-таблицы за <span class="arithmatex">\(O(1)\)</span> времени, поэтому она очень эффективна.</li>
<li>К типичным операциям хеш-таблицы относятся поиск, добавление пары ключ-значение, удаление пары ключ-значение и обход хеш-таблицы.</li>
<li>Хеш-функция отображает <code>key</code> в индекс массива, после чего можно обратиться к соответствующему бакету и получить <code>value</code> .</li>
<li>Два разных <code>key</code> после хеш-функции могут дать один и тот же индекс массива, что приводит к ошибочному результату поиска; это явление называется хеш-коллизией.</li>
<li>Два разных <code>key</code> после хеш-функции могут дать один и тот же индекс массива, что приводит к ошибочному результату поиска. Это явление называется хеш-коллизией.</li>
<li>Чем больше емкость хеш-таблицы, тем ниже вероятность хеш-коллизий. Поэтому хеш-коллизии можно смягчать путем расширения хеш-таблицы. Как и у массива, операция расширения у хеш-таблицы очень затратна.</li>
<li>Коэффициент загрузки определяется как отношение числа элементов в хеш-таблице к числу бакетов, отражает степень серьезности хеш-коллизий и часто используется как условие запуска расширения хеш-таблицы.</li>
<li>Метод цепочек превращает одиночный элемент в связный список и хранит все конфликтующие элементы в одном списке. Однако слишком длинный список снижает эффективность поиска, поэтому его можно дополнительно преобразовать в красно-черное дерево.</li>
@@ -4382,12 +4382,12 @@
<p>Во-первых, у хеш-таблицы повышается временная эффективность, но снижается пространственная эффективность. Значительная часть ее памяти остается неиспользованной.</p>
<p>Во-вторых, она быстрее только в определенных сценариях. Если одну и ту же задачу можно реализовать на массиве или связном списке с той же асимптотикой, то часто такая реализация окажется быстрее, чем хеш-таблица. Причина в том, что вычисление хеш-функции само по себе стоит времени, то есть константа в сложности получается выше.</p>
<p>Наконец, временная сложность хеш-таблицы тоже может деградировать. Например, при методе цепочек мы все равно выполняем поиск в связном списке или красно-черном дереве, поэтому риск деградации до <span class="arithmatex">\(O(n)\)</span> сохраняется.</p>
<p><strong>Q</strong>: Есть ли у повторного хеширования недостаток "нельзя напрямую удалять элементы"? Можно ли повторно использовать место, помеченное как удаленное?</p>
<p><strong>Q</strong>: Есть ли у повторного хеширования недостаток «нельзя напрямую удалять элементы»? Можно ли повторно использовать место, помеченное как удаленное?</p>
<p>Повторное хеширование - это разновидность открытой адресации, а у всех методов открытой адресации есть недостаток: элементы нельзя удалять напрямую, поэтому приходится использовать метку удаления. Пространство, помеченное как удаленное, можно использовать повторно. Когда новый элемент вставляется в хеш-таблицу и в процессе пробирования попадает на такую отмеченную позицию, эта позиция может быть занята новым элементом. Такой подход сохраняет последовательность пробирования и одновременно поддерживает приемлемую эффективность использования памяти.</p>
<p><strong>Q</strong>: Почему при линейном пробировании во время поиска элемента вообще возникает хеш-коллизия?</p>
<p>Во время поиска мы через хеш-функцию находим соответствующий бакет и соответствующую пару ключ-значение, но видим, что <code>key</code> не совпадает, а это и означает наличие хеш-коллизии. Поэтому метод линейного пробирования в соответствии с заранее заданным шагом последовательно движется дальше, пока не найдет правильную пару ключ-значение или не убедится, что поиск завершился неудачей.</p>
<p><strong>Q</strong>: Почему расширение хеш-таблицы помогает смягчать хеш-коллизии?</p>
<p>Последний шаг хеш-функции обычно состоит во взятии по модулю длины массива <span class="arithmatex">\(n\)</span> , чтобы результат попадал в диапазон индексов массива; после расширения длина массива <span class="arithmatex">\(n\)</span> меняется, а значит, может измениться и индекс, соответствующий данному <code>key</code> . Несколько <code>key</code> , которые раньше попадали в один бакет, после расширения могут распределиться по нескольким бакетам, и тем самым хеш-коллизии будут ослаблены.</p>
<p>Последний шаг хеш-функции обычно состоит во взятии по модулю длины массива <span class="arithmatex">\(n\)</span> , чтобы результат попадал в диапазон индексов массива. После расширения длина массива <span class="arithmatex">\(n\)</span> меняется, а значит, может измениться и индекс, соответствующий данному <code>key</code> . Несколько <code>key</code> , которые раньше попадали в один бакет, после расширения могут распределиться по нескольким бакетам, и тем самым хеш-коллизии будут ослаблены.</p>
<p><strong>Q</strong>: Если нам нужен быстрый доступ, почему бы просто не использовать массив?</p>
<p>Когда <code>key</code> данных - это непрерывные целые числа из маленького диапазона, действительно можно напрямую использовать массив: это просто и эффективно. Но если <code>key</code> имеют другой тип данных (например, строки), тогда нужен хеш-алгоритм, который отобразит <code>key</code> в индекс массива, а хранение элементов будет выполняться через массив бакетов. Такая структура и называется хеш-таблицей.</p>