Чи можуть насправді хеш-таблиці бути O (1)?


114

Здається, загальновідомо, що хеш-таблиці можуть досягти O (1), але це ніколи не мало для мене сенсу. Може хтось, будь ласка, пояснить це? Ось дві ситуації, які приходять на думку:

A. Значення є int, меншим за розмір хеш-таблиці. Тому значення - це власний хеш, тому немає хеш-таблиці. Але якби це було, це було б O (1) і все-таки було б неефективним.

B. Ви повинні обчислити хеш значення. У цій ситуації порядок становить O (n) для розміру даних, що шукаються. Пошук може бути O (1) після того, як ви зробите O (n) роботу, але це все одно виходить на O (n) в моїх очах.

І якщо у вас ідеальний хеш або велика хеш-таблиця, мабуть, декілька предметів на відро. Отже, це все одно перетворюється на невеликий лінійний пошук.

Я думаю, що хеш-таблиці є приголомшливими, але я не отримую позначення O (1), якщо це просто не повинно бути теоретичним.

Стаття Вікіпедії для хеш-таблиць послідовно посилається на постійний час пошуку і повністю ігнорує вартість хеш-функції. Це справді справедлива міра?


Редагувати: щоб узагальнити те, що я дізнався:

  • Це технічно вірно, тому що хеш-функція не потрібна для використання всієї інформації в ключі, і тому це може бути постійним часом, а тому, що достатньо велика таблиця може звести зіткнення майже до постійного часу.

  • Це практично на практиці, оскільки з часом воно просто працює, поки вибрано хеш-функцію та розмір таблиці, щоб мінімізувати зіткнення, хоча це часто означає не використовувати функцію хешування постійного часу.


31
Це амортизований O (1), а не O (1).
kennytm

Пам'ятайте, що O () - це межа для великої кількості операцій. У середньому у вас багато зіткнень - не обов'язково, щоб окрема операція не мала зіткнень.
Мартін Бекетт

Залежно від реалізації рядків, рядки можуть носити навколо себе хешоване значення, тож це буде постійним. Справа в тому, що це не має значення для складності пошуку хешу.
Річ Ремер

@kennytm Звичайно, пошук після того, як ви хешировали вхід , амортизується O (1). Але хіба вартість обчислення хесу насправді незначна? Припустимо, ми хешируем рядок - символьний масив. Щоб генерувати хеш, кожен символ повторюється, тому хешування рядка є O (N), де N - довжина рядка. Ось як це задокументовано для C #, і ось як hashCode()реалізований метод Java для String. grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…
spaaarky21

1
@ spaaarky21 N в O (N), про який ви говорите, - це довжина рядка, яка відрізняється від n розміром хеш-таблиці. Відповідь Марка Байєра вже вирішила це.
kennytm

Відповіді:


65

Тут у вас є дві змінні, m і n, де m - довжина вводу, а n - кількість елементів у хеші.

Заява про ефективність пошуку O (1) робить щонайменше два припущення:

  • Ваші об'єкти можуть бути рівними порівняно за O (1) час.
  • Буде мало хеш-зіткнень.

Якщо ваші об'єкти змінного розміру і перевірка рівності вимагає перегляду всіх бітів, тоді продуктивність стане O (m). Однак хеш-функція не повинна бути O (m) - це може бути O (1). На відміну від криптографічного хеша, хеш-функція для використання у словнику не повинна дивитись на кожен біт у вхідних даних, щоб обчислити хеш. Реалізація може переглядати лише фіксовану кількість біт.

Для достатньо багатьох предметів кількість елементів стане більшою, ніж кількість можливих хешів, і тоді ви отримаєте зіткнення, що спричинить підвищення продуктивності вище O (1), наприклад O (n) для простого переходу пов'язаного списку (або O (n * м) якщо обидва припущення помилкові).

На практиці, хоча твердження O (1), хоча технічно є помилковим, приблизно відповідає дійсності для багатьох реальних ситуацій, і особливо для тих ситуацій, коли вищезазначені припущення мають місце.


4
Як і вищезазначене, якщо ви використовуєте незмінні об'єкти в якості ключів, наприклад, Java Strings, обчисливши хеш один раз, ви можете запам'ятати його і не доведеться обчислювати його знову. З іншого боку, зазвичай не можна покластися на хеш, щоб сказати, чи однакові два ключі, коли ви знайшли правильне відро, тому для рядків вам потрібно зробити обхід O (m), щоб дізнатися, чи рівні вони.
JeremyP

1
@JeremyP: Хороший момент порівняння рівності O (m). Я пропустив це - оновлений пост. Дякую!
Марк Байєрс

2
O(1)Твердження вірне , якщо ви хешування intз або що - то ще , що вміщується в машинному слові. Саме це передбачає більшість теорій хешування.
Томас Ейл

Мені подобається це пояснення вашого Марка, я його процитував у своїй статті про хеш-таблиці на meshfields.de/hash-tables
Стів К

3
У "m - довжина вводу" - введення занадто розпливчасте - це може означати, що всі ключі та значення вставляються, але це стане зрозуміло пізніше (принаймні для тих, хто вже розуміє тему) ви маєте на увазі ключ . Просто пропонуємо використовувати «ключ» у відповіді для наочності. BTW - конкретний приклад - std::hashтекстові клавіші Visual C ++ поєднують 10 символів, рівномірно розташованих вздовж тексту, у хеш-значенні, тож це O (1) незалежно від довжини тексту (але значно більше схильних до зіткнення, ніж GCC!). Окремо твердження O (1) мають ще одне припущення (як правило, правильно), що m набагато менше n .
Тоні Делрой

22

Ви повинні обчислити хеш, тож порядок є O (n) для розміру даних, що шукаються. Пошук може бути O (1) після того, як ви зробите O (n) роботу, але це все одно виходить на O (n) в моїх очах.

Що? Для хешування одного елемента потрібен постійний час. Чому це було б щось інше? Якщо ви вставляєтеn елементи, то так, вам доведеться обчислити nхеші, і для цього потрібен лінійний час ... щоб переглянути елемент вгору, ви обчислите один хеш того, що шукаєте, а потім знайдіть відповідне відро з цим . Ви не перераховуєте хеші всього, що вже є в хеш-таблиці.

І якщо у вас ідеальний хеш або велика хеш-таблиця, напевно, є кілька предметів на відро, тож у будь-який момент воно переходить у невеликий лінійний пошук.

Не обов'язково. Цебра не обов'язково повинні бути списками або масивами, вони можуть бути будь-якого типу контейнерів, наприклад, збалансованим BST. Це означає O(log n)найгірший випадок. Але саме тому важливо вибрати гарну функцію хешування, щоб уникнути занадто багато елементів в одне відро. Як зазначав KennyTM, у середньому ви все одно отримаєтеO(1) час, навіть якщо час від часу вам доведеться копати відро.

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


В одному з інших коментарів ви згадуєте використання рядків як ключів. Ви стурбовані тим, скільки часу потрібно для обчислення хеша рядка, оскільки він складається з декількох символів? Як хтось ще раз зазначив, вам не обов’язково потрібно дивитися на всі знаки, щоб обчислити хеш, хоча це може створити кращий хеш, якщо ви це зробили. У такому випадку, якщо mу вашому ключі є середні знаки, і ви використовували їх для обчислення вашого хешу, то, мабуть, ви праві, такі пошуки знадобляться O(m). Якщо m >> nтоді у вас можуть виникнути проблеми. Вам, мабуть, буде краще з BST у такому випадку. Або виберіть більш дешеву функцію хешування.


хеш-таблиці не використовують BST. BST не вимагають хеш-значень. Карти та набори можна реалізувати як BST.
Нік Дандулакіс

3
@Nick: Так? Ні ... BST не вимагають хеш-значень ... в цьому справа. Ми припускаємо, що на даний момент у нас вже є зіткнення (той самий хеш ... або принаймні таке ж відро), тому нам потрібно подивитися на щось інше, щоб знайти потрібний елемент, тобто фактичне значення.
вересня

о, я бачу вашу думку. Але я не впевнений, що змішування BSTs та хешей варте клопоту. Чому б просто не використовувати BST?
Нік Дандулакіс

2
Я просто кажу, що ти могли позбутися цього O(n)за зіткнення. Якщо будуть очікує багато зіткнень, то ви маєте рацію, ймовірно , краще йти з BST в першу чергу.
вересня

1
@ spaaarky21 Правильно, але Nв цьому випадку - довжина рядка. Нам потрібно лише один хеш рядки, щоб визначити, яке «відро» йому потрібно ввійти - воно не зростає з довжиною хешмапу.
mpen

5

Хеш фіксованого розміру - пошук відповідного хеш-відра є операцією з фіксованою вартістю. Це означає, що це O (1).

Обчислення хешу не повинно бути особливо дорогою операцією - тут ми не говоримо про криптографічні хеш-функції. Але це побіжно. Розрахунок хеш-функції сам по собі не залежить від кількості n елементів; хоча це може залежати від розміру даних у елементі, це n не стосується n . Отже, обчислення хеша не залежить від n і також є O (1).


3
шукаючи хеш-відро - це O (1). Але розміщення правої клавіші - це процедура O (n), де n залежить від кількості зіткнень хешу.
Нік Дандолакіс

1
Отже, з 3 кроків обчисліть хеш, знайдіть відро, шукайте відро, середній крок - постійний? Пошук у відрі зазвичай постійний. Обчислення хешу зазвичай на кілька порядків дешевше, ніж інші засоби пошуку відра. Але чи насправді це додає до постійного часу? У наївному пошуку підрядків ви б сказали O (n * m) на дві довжини, то чому чому тут не враховується довжина ключа?
розіграш

знаходження ключа з фіксованою довжиною є лише O (n), тільки якщо її список підтримується, врівноважена хеш-таблиця, підтримувана деревом, буде O (log (n))
jk.

@Jk Для хороших хеш - функцій, в гіршому випадку завжди lognдивіться моя відповідь на stackoverflow.com/questions/4553624/hashmap-get-put-complexity / ...
Томас Ахле

У гіршому випадку складність буде o (n) у разі зіткнення
Saurabh Chandra Patel

3

Хеширование - це O (1), тільки якщо в таблиці є лише постійне число клавіш і зроблено деякі інші припущення. Але в таких випадках це має перевагу.

Якщо ваш ключ має n-бітове представлення, ваша хеш-функція може використовувати 1, 2, ... n з цих бітів. Думаючи про хеш-функцію, яка використовує 1 біт. Оцінка точно О (1). Але ви розділяєте лише простір ключів на 2. Отже, ви відображаєте цілих 2 ^ (n-1) ключі в один і той же бін. використовуючи пошук BST, для пошуку конкретного ключа, якщо він майже заповнений, потрібно до n-1 кроків.

Ви можете розширити це, щоб побачити, що якщо ваша хеш-функція використовує K біт, розмір вашого біна дорівнює 2 ^ (nk).

тому K-бітова хеш-функція ==> не більше 2 ^ К ефективних бін ==> до 2 ^ (nK) n-бітових клавіш на bin ==> (nK) кроків (BST) для вирішення зіткнень. Насправді більшість хеш-функцій набагато менш "ефективні" і потребують / використовують більше K бітів для отримання 2 ^ k бін. Тож навіть це оптимістично.

Ви можете переглянути це таким чином - вам знадобиться ~ n кроків, щоб мати можливість однозначно розрізнити пару клавіш з n біт у гіршому випадку. Дійсно немає способу обійти цю межу теорії інформації, хеш-таблицю чи ні.

Однак це НЕ як / коли ви використовуєте хеш-таблицю!

Аналіз складності передбачає, що для n-бітових ключів у таблиці ви можете мати клавіші O (2 ^ n) (наприклад, 1/4 всіх можливих клавіш). Але більшість, якщо не весь час ми використовуємо хеш-таблицю, у нас є лише постійна кількість n-бітних клавіш у таблиці. Якщо ви хочете лише постійну кількість клавіш у таблиці, скажімо, C - це ваше максимальне число, тоді ви можете сформувати хеш-таблицю бін O (C), що гарантує очікуване постійне зіткнення (з хорошою хеш-функцією); і хеш-функцію, використовуючи ~ logC з n бітів у ключі. Тоді кожен запит - O (logC) = O (1). Ось як люди стверджують, що "доступ до хеш-таблиці - це O (1)" /

Тут є декілька уловів - по-перше, кажучи, що вам не потрібні всі біти, можливо, це лише витівка. По-перше, ви не можете реально передати ключове значення хеш-функції, оскільки це було б переміщенням n бітів у пам'яті, яка є O (n). Тому вам потрібно зробити, наприклад, проходження посилання. Але вам все одно потрібно зберігати його десь, що вже було операцією O (n); ви просто не виставляєте його на хешування; ви загальної задачі з обчислення не можете цього уникнути. По-друге, ви робите хешування, знаходите контейнер і знайшли більше 1 ключа; Ваша вартість залежить від вашого способу вирішення - якщо ви будете робити порівняння (BST або List), ви матимете операцію O (n) (ключ виклику n-бітний); якщо ви займаєтесь другим хешем, то у вас є те саме питання, якщо у другого хеша зіткнення.

Розглянемо альтернативу, наприклад BST, у цьому випадку. є клавіші C, тому врівноважений BST буде O (logC) по глибині, тому пошук виконує кроки O (logC). Однак порівняння в цьому випадку було б операцією O (n) ... тому, здається, хеширование - кращий вибір у цьому випадку.


1

TL; DR: Таблиці хешу гарантують O(1)очікуваний найгірший час, якщо вибираєте хеш-функцію навмання рівномірно з універсального сімейства хеш-функцій. Очікуваний найгірший випадок не такий, як середній випадок.

Відмова: Я офіційно не O(1)доводжу хеш-таблиці , тому що перегляньте це відео з курсу [ 1 ]. Я також не обговорюю амортизованого аспекти хеш-таблиць. Це є ортогональним для дискусії про хеширування та зіткнення.

Я бачу напрочуд велику плутанину навколо цієї теми в інших відповідях та коментарях, і спробую виправити деякі з них у цій довгій відповіді.

Обґрунтування найгіршого випадку

Існують різні типи аналізу найгіршого випадку. Аналіз, який на даний момент зробили більшість відповідей, - це не найгірший випадок, а скоріше середній випадок [ 2 ]. Середній аналіз випадків, як правило, більш практичний. Можливо, ваш алгоритм має один з найгірших вхідних випадків, але насправді добре працює на всіх інших можливих введеннях. Підсумок - ваш час виконання залежить від набору даних який ви працюєте.

Розглянемо наступний псевдокод getметоду хеш-таблиці. Тут я припускаю, що ми вирішуємо зіткнення ланцюгом, тому кожен запис таблиці є зв'язаним списком (key,value)пар. Ми також припускаємо, що кількість відра mє фіксованою, але є O(n), де nкількість елементів на вході.

function get(a: Table with m buckets, k: Key being looked up)
  bucket <- compute hash(k) modulo m
  for each (key,value) in a[bucket]
    return value if k == key
  return not_found

Як вказували інші відповіді, це відбувається в середньому O(1)та найгіршому випадкуO(n) . Тут ми можемо зробити невеликий ескіз доказу, оскаржуючи. Завдання полягає в наступному:

(1) Ви даєте свій алгоритм хеш-таблиці противнику.

(2) Противник може вивчити його і готувати, поки хоче.

(3) Нарешті, супротивник дає введення розміру, nякий потрібно вставити у вашу таблицю.

Питання полягає в тому, наскільки швидко ваша хеш-таблиця на супротивному вході?

З кроку (1) противник знає вашу хеш-функцію; під час кроку (2) супротивник може скласти список nелементів з тим самим hash modulo m, наприклад, випадковим чином обчисливши хеш купки елементів; і тоді в (3) вони можуть надати вам цей список. Але ось і ось, оскільки всі nелементи хешуються до одного відра, вашому алгоритму знадобиться O(n)час, щоб перейти пов'язаний список у цьому відрі. Незалежно від того, скільки разів ми повторюємо виклик, супротивник завжди виграє, і саме так поганий ваш алгоритм, в гіршому випадку O(n).

Як дістається хешування O (1)?

Те, що нас відкинуло в попередньому виклику, було те, що супротивник дуже добре знав нашу хеш-функцію, і міг використати ці знання для створення найгіршого можливого вкладу. Що робити, якщо замість того, щоб завжди використовувати одну фіксовану хеш-функцію, ми насправді мали набір хеш-функцій H, які алгоритм може випадково вибирати під час виконання? У випадку, якщо вам цікаво, Hйого називають універсальним сімейством хеш-функцій [ 3 ]. Добре, спробуємо додати до цього деяку випадковість .

Спершу припустимо, що наша хеш-таблиця також включає насіння rта rїї присвоюють випадковому числу на час створення. Ми призначаємо його один раз, а потім він фіксується для цього екземпляра хеш-таблиці. Тепер переглянемо наш псевдокод.

function get(a: Table with m buckets and seed r, k: Key being looked up)
  rHash <- H[r]
  bucket <- compute rHash(k) modulo m
  for each (key,value) in a[bucket]
    return value if k == key
  return not_found

Якщо ми спробуємо виклик ще раз: з кроку (1) супротивник може знати всі хеш-функції, які ми маємо H, але тепер залежить від конкретної хеш-функції, яку ми використовуємо r. Значення rдля нашої структури приватне, супротивник не може перевірити його під час виконання, ні передбачити його достроково, тому він не може скласти список, який для нас завжди поганий. Припустимо , що на стадії (2) противник вибирає одну функцію hashв Hвипадковим чином , він потім обробляє список nзіткнень під hash modulo m, і посилає його на стадії (3), перетинаючи пальці , що під час виконання H[r]будуть однаковими hashвони вибрали.

Це серйозна ставка для супротивника, список, під яким він склав, стикається hash, але буде просто випадковим входом під будь-яку іншу хеш-функцію в H. Якщо він виграє цю ставку, наш час запуску буде найгіршим випадком, O(n)як і раніше, але якщо він програє, то добре, нам просто дають випадковий внесок, який займає середній O(1)час. І справді більшість разів противник програє, він виграє лише один раз кожні |H|виклики, і ми можемо зробити |H|дуже великими.

Порівняйте цей результат з попереднім алгоритмом, коли супротивник завжди вигравав виклик. Handwaving тут трохи, але так як більшість раз противник зазнає невдачі, і це вірно для всіх можливих стратегій противник може спробувати, то хоча найгірший випадок O(n), то очікується , в гіршому випадку , насправді O(1).


Знову ж таки, це не формальне підтвердження. Гарантія, яку ми отримуємо від цього очікуваного найгіршого аналізу, полягає в тому, що наш час запуску не залежить від конкретного вкладу . Це справді випадкова гарантія, на відміну від середнього аналізу випадків, коли ми показали, що мотивований противник може легко створити погані дані.


0

Є два параметри, за допомогою яких можна отримати О (1) найгірший час.

  1. Якщо ваша установка статична, то хешування FKS отримає найгірші гарантії O (1) . Але, як ви вказали, ваше налаштування не є статичним.
  2. Якщо ви використовуєте хешування зозулі, то запити та видалення - це найгірший варіант (1) , але очікується лише вставлення O (1) . Хеширование зозулі працює досить добре, якщо у вас є верхня межа загальної кількості вставок, а розмір столу буде приблизно на 25% більшим.

Скопійовано звідси


0

Виходячи з обговорення тут, якщо X - це стеля (# елементів у таблиці / # бін), то кращою відповіддю є O (log (X)), припускаючи ефективну реалізацію пошуку bin.


0

A. Значення є int, меншим за розмір хеш-таблиці. Тому значення - це власний хеш, тому немає хеш-таблиці. Але якби це було, це було б O (1) і все-таки було б неефективним.

Це випадок, коли ви можете тривіально відображати ключі для відрізних відро, тому масив здається кращим вибором структури даних, ніж хеш-таблиця. Однак неефективність не зростає з розміром таблиці.

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

B. Ви повинні обчислити хеш значення. У цій ситуації порядок становить O (n) для розміру даних, що шукаються. Пошук може бути O (1) після того, як ви зробите O (n) роботу, але це все одно виходить на O (n) в моїх очах.

Нам потрібно розрізняти розмір ключа (наприклад, в байтах) і розмір кількості ключів, що зберігаються в хеш-таблиці. Твердження хеш-таблиць забезпечують операції O (1) означають, що операції (вставити / видалити / знайти) не мають тенденції до подальшого сповільнення, оскільки кількість клавіш збільшується від сотень до тисяч мільйонів до мільярдів (принаймні, не, якщо всі дані доступ до / оновлення в однаково швидкій пам’яті, будь то оперативна пам’ять або диск-кеш-ефекти, можливо, вступають у гру, але навіть вартість пропуску кеш-пам'яті в гіршому випадку має тенденцію до постійного кратного удару в найкращому випадку).

Подумайте про телефонну книгу: у вас можуть бути імена, які є досить довгими, але якщо книга має 100 імен, або 10 мільйонів, середня довжина імені буде досить послідовною, і найгірший випадок в історії ...

Світовий рекорд Гіннесса за найдовше ім'я, яке використовували будь-хто хто-небудь коли-небудь, встановив Адольф Блейн Чарльз Девід Граф Фредерік Джеральд Гюберт Ірвін Джон Кеннет Ллойд Мартін Нерон Олівер Пол Квінсі Рендолф Шерман Томас Ункас Віктор Вільям Ксеркс Янсі Вольфшлегельштайнгаузенбергердорф, старший

... wcкаже мені , що це 215 символів - це не жорсткий верхньої межі з довжиною ключа, але ми не повинні турбуватися про там бути масово більше.

Це стосується більшості хеш-таблиць реального світу: середня довжина клавіш не має тенденції до зростання з використанням кількості клавіш. Існують винятки, наприклад, програма створення ключів може повертати рядки, в які вбудовуються цілі числа, але навіть тоді, коли ви збільшуєте кількість клавіш на порядок, ви збільшуєте лише довжину ключа на 1 символ: це не суттєво.

Можна також створити хеш із кількості ключових даних фіксованого розміру. Наприклад, Visual C ++ Microsoft поставляється зі стандартною реалізацією бібліотеки, std::hash<std::string>яка створює хеш, що включає лише десять байтів, рівномірно розташованих уздовж рядка, тому, якщо рядки змінюються лише за іншими показниками, ви отримуєте зіткнення (а отже, на практиці не O (1) поведінки на пошуковій стороні після зіткнення), але час створення хеша має жорстку верхню межу.

І якщо у вас ідеальний хеш або велика хеш-таблиця, мабуть, декілька предметів на відро. Отже, це все одно перетворюється на невеликий лінійний пошук.

Як правило, правда, але дивовижним у хеш-таблицях є те, що кількість клавіш, відвіданих під час цих "малих лінійних пошуків", - для окремого ланцюгового підходу до зіткнень - є функцією коефіцієнта завантаження хеш-таблиці (відношення ключів до відра).

Наприклад, з коефіцієнтом навантаження 1,0 дорівнює тривалість цих лінійних пошуків в середньому ~ 1,58, незалежно від кількості клавіш (див. Мою відповідь тут ). Для закритого хешування це трохи складніше, але не набагато гірше, коли коефіцієнт навантаження не надто високий.

Це технічно вірно, тому що хеш-функція не потрібна для використання всієї інформації в ключі, і тому це може бути постійним часом, а тому, що достатньо велика таблиця може звести зіткнення майже до постійного часу.

Цей вид пропускає суть. Будь-яка структура асоціативної інформації в кінцевому підсумку іноді повинна виконувати операції над кожною частиною ключа (нерівність іноді може бути визначена лише з частини ключа, але рівність, як правило, вимагає враховувати кожен біт). Як мінімум, він може один раз хешувати ключ і зберігати хеш-значення, і якщо він використовує досить сильну хеш-функцію - наприклад, 64-бітний MD5 - він може практично ігнорувати навіть можливість хешування двох клавіш до одного значення (компанія Я працював, робив саме це для розподіленої бази даних: час генерації хеша все ще був незначним у порівнянні з мережевими передачами на всій WAN). Отже, не так вже й багато сумнівів у витратах на обробку ключа: це властиво зберіганню ключів незалежно від структури даних, і, як було сказано вище, -

Що стосується досить великих хеш-таблиць, що призводять до зіткнення, то тут також не вистачає суті. Для окремого ланцюга у вас все ще є постійна середня довжина ланцюга зіткнення при будь-якому даному коефіцієнті навантаження - це просто вище, коли коефіцієнт навантаження більший, а це відношення нелінійне. Користувач ТА Ганс коментує мою відповідь, також пов'язану вище :

середня довжина відра, обумовлена ​​непустими відрами, є кращим показником ефективності. Це a / (1-e ^ {- a}) [де a - коефіцієнт навантаження, e - 2.71828 ...]

Таким чином, коефіцієнт навантаження в поодинці визначає середнє число стикаються ключів ви повинні шукати в процесі вставки / стирання / знайти роботу. Для роздільного ланцюга не просто підходити до постійності, коли коефіцієнт навантаження низький - він завжди постійний. Для відкритого звернення, хоча ваша претензія має деяку обґрунтованість: деякі стикаються елементи переадресовуються на альтернативні відра та можуть перешкоджати операціям на інших клавішах, тому при більш високих коефіцієнтах навантаження (особливо> .8 або .9) довжина ланцюга зіткнення стає значно гіршою.

Це практично на практиці, оскільки з часом воно просто працює, поки вибрано хеш-функцію та розмір таблиці, щоб мінімізувати зіткнення, хоча це часто означає не використовувати функцію хешування постійного часу.

Ну, розмір столу повинен спричинити розумний коефіцієнт навантаження, враховуючи вибір закритого хешування або окремого ланцюжка, але також якщо хеш-функція трохи слабка і ключі не дуже випадкові, наявність простої кількості відра часто допомагає зменшити зіткнення теж ( hash-value % table-sizeтоді загортання навколо таких, що зміни лише біта високого порядку в хеш-значенні все ще вирішуються на відра, що поширюються псевдо випадковим чином по різних частинах хеш-таблиці).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.