Огляд простого хеш-таблиці
Як оновлення, хеш-таблиця - це спосіб збереження значення під певним ключем у структурі даних. Наприклад, я можу зберігати значення "a"
під ключем 1
, а потім пізніше отримати його, шукаючи ключ 1
у хеш-таблиці.
Найпростіший приклад хеш-таблиці, яку я можу придумати вгорі голови, - хеш-таблиця, яка може зберігати лише цілі числа, де ключем для запису хеш-таблиці є також значення, яке зберігається. Скажімо, ваша таблиця розміру 8, і це в основному масив пам'яті:
---------------------------------
| | | | | | | | |
---------------------------------
0 1 2 3 4 5 6 7
Функція хешу
Функції хешу дають вам індекс, де зберігати свою вартість. Досить простий хеш - функції для цієї таблиці можна було б додати 1 до значення ви хочете зберегти, а потім мод його на 8 (розмір таблиці). Іншими словами, ваш хеш - функція (n+1)%8
, де n
є ціле число ви хочете зберегти.
Вкладиші
Якщо ви хочете вставити значення в цю хеш-таблицю, ви викликаєте свою хеш-функцію (у цьому випадку (n+1)%8
) на значення, яке ви хочете вставити, щоб дати вам індекс. Наприклад, якщо ми хочемо вставити 14, ми зателефонуємо (14 + 1) % 8
та отримаємо індекс 7
, тому ми би вставили йому значення в індекс 7
.
---------------------------------
| | | | | | | |14 |
---------------------------------
0 1 2 3 4 5 6 7
Аналогічно ми можемо вставити 33, 82 та 191 так:
---------------------------------
|191| |33 |82 | | | |14 |
---------------------------------
0 1 2 3 4 5 6 7
Зіткнення
Але що трапиться, якщо ми спробуємо вставити щось, що зіткнеться із записом? 2 має йти в індексі 3
, але він бере 82. Існує кілька способів вирішити цю проблему, найпростіший - викликати нашу хеш-функцію знову і знову повторно, поки не знайдемо порожній пробіл.
Тож логіка така:
- (2 + 1)% 8 = 3
- Індекс 3 заповнений
- Підключіть 3 до нашої хеш-функції. ( 3 + 1)% 8 = 4 , який порожній.
- Помістіть наше значення в індекс 4 .
Тепер хеш-таблиця виглядає приблизно так, що значення 2 зберігається в індексі 4
.
---------------------------------
|191| |33 |82 |2 | | |14 |
---------------------------------
0 1 2 3 4 5 6 7
Мінус цього рішення полягає в тому, що досить скоро наш стіл буде заповнений! Якщо ви знаєте, що розмір ваших даних обмежений, це не повинно бути проблемою, якщо ваша таблиця досить велика, щоб вмістити всі можливі значення. Якщо ви хочете мати більше зусиль, ви можете вирішити зіткнення по-різному. Повернемось туди, де ми були, перш ніж вставляти 2.
---------------------------------
|191| |33 |82 | | | |14 |
---------------------------------
0 1 2 3 4 5 6 7
Якщо ви пам’ятаєте, (2+1)%8
дає нам індекс 3
, який беремо. Якщо ви не хочете, щоб ваша хеш-таблиця заповнювалася, ви можете використовувати індекс таблиці як пов'язаний список і додавати до списку в цьому індексі. Тож замість того, щоб викликати хеш-функцію ще раз, ми просто додамо до списку в індексі 3
:
-----
| 2 |
---------------------------------
|191| |33 |82 | | | |14 |
---------------------------------
0 1 2 3 4 5 6 7
Цей список може зростати стільки, скільки дозволить пам'ять. Я можу вставити 18, і він буде просто доданий до 2:
-----
|18 |
-----
| 2 |
---------------------------------
|191| |33 |82 | | | |14 |
---------------------------------
0 1 2 3 4 5 6 7
Пошук
Пошук значень у вашій хеш-таблиці швидкий, враховуючи, що ваша хеш-таблиця має досить великий розмір. Ви просто викликаєте свою хеш-функцію та отримуєте індекс. Скажімо, ви хочете подивитися, чи є 82 у вашій таблиці. Функція пошуку закликала б (82+1)%8
= 3
, і перегляне елемент у індексі 3
та поверне його вам. Якщо ви подивилися на 16, функція пошуку виглядала б в індексі 1
та бачила, що її не існує.
Шукати потрібно і для зіткнення!
Якщо ви спробуєте знайти значення 2, ваша хеш-таблиця повинна використовувати ту саму логіку зіткнення, яку вона використовувала для зберігання даних, як і для отримання даних. Залежно від того, як працює ваша хеш-таблиця, ви або будете хешувати ключ знову і знову, поки не знайдете потрібну запис (або знайдете порожнє місце), або ви будете повторювати ваш зв'язаний список, поки не знайдете елемент (або дійшов до кінця списку)
Підсумок
Отже, хеш-таблиці - хороший спосіб швидкого зберігання та доступу до пар «ключ-значення». У цьому прикладі ми використовували той самий ключ, що і значення, але в хеш-таблицях реального світу ключі не такі обмежені. Функції хешу працюватимуть на клавішах для генерування індексу, і тоді ключ / значення може бути збережено в цьому індексі. Таблиці хешу насправді не призначені для повторення, хоча це можна зробити. Як бачите, у хеш-таблицях може бути багато порожніх пробілів, і повторення через них буде марною тратою часу. Навіть якщо у хеш-таблиці є логіка пропускання порожніх просторів у своєму ітераторі, вам краще підійде структура даних, призначена для ітераторів, як пов'язані списки.