Вам не вистачає того, як обидві структури даних справляються з хеш-зіткненнями. Фільтри цвітіння не зберігають фактичних значень, тому необхідний простір - це постійний розмір позначеного масиву. Натомість, якщо ви використовуєте традиційний хеш, він намагається зберігати всі цінність, які ви йому надаєте, тому він росте з часом.
Розглянемо спрощену хеш-функцію (лише для прикладу!) f(x) = x % 2
. Тепер ви вводите наступні цілі числа: 2, 3, 4, 5, 6, 7
.
Стандартний хеш: задані значення будуть хешировані, і ми закінчимось великою кількістю зіткнень через f(2) = f(4) = f(6) = 0
і f(3) = f(5) = f(7) = 1
. Тим не менш, хеш зберігає всі ці значення, і він зможе сказати вам, що 8
він не зберігається в ньому. Як це робити? Він відслідковує зіткнення та зберігає всі значення з однаковим хеш-значенням, тоді, коли ви запитуєте його, він додатково порівнює ваш запит. Тож давайте запитаємо карту для 8
:, f(8) = 0
то вона загляне у відро, куди ми вже вставили, 2, 4, 6
і потрібно зробити 3 порівняння, щоб сказати, що 8
це не було частиною вводу.
Фільтр цвітіння: зазвичай кожне вхідне значення хеширується щодо k
різних хеш-функцій. Знову ж таки, для простоти припустимо, що ми використовуємо лише функцію одиночного хешу f
. Тоді нам потрібен масив з 2 значень, і коли ми стикаємося з введенням, 2
це означає, що завдяки f(2) = 0
значенню масиву в позиції ми встановимо 0
значення 1
. Те саме відбувається 4
і для 6
. Аналогічно, 3, 5, 7
кожен вхід встановлює значення масиву 1
на значення 1
. Тепер ми запитуємо, чи 8
був частиною введення: f(8) = 0
і масив у положенні 0
є 1
, тож фільтр розквітання буде помилково стверджувати, що він 8
був дійсно частиною введення.
Щоб зробити трохи більш реалістичним, розглянемо, що ми додамо другу функцію хешу g(x) = x % 10
. З цим вхідне значення 2
веде до двох хеш-значень, f(2) = 0
і g(2) = 2
два відповідні позиції масиву будуть встановлені на 1
. Звичайно, масив тепер повинен бути як мінімум розміром 10
. Але коли ми запитуємо, 8
ми перевіримо масив у позиції 8
через g(8) = 8
, і ця позиція все ще буде 0
. Ось чому додаткові хеш-функції зменшують помилкові позитиви, які ви отримаєте.
Порівняння: Фільтр цвітіння використовує k
хеш-функції, що означає доступ до k
випадкових позицій масиву. Але ця цифра точна. Натомість хеш гарантує вам лише амортизований постійний час доступу, але може дегенеруватися залежно від характеру вашої хеш-функції та вхідних даних. Так це зазвичай швидше, за винятком випадків дегенерування.
Однак, коли у вас зіткнення хешу, стандартний хеш повинен буде перевірити рівність збережених значень проти значення запиту. Ця перевірка рівності може бути довільно дорогою і ніколи не відбуватиметься з фільтром цвітіння.
З точки зору простору, фільтр цвітіння є постійним, оскільки ніколи не потрібно використовувати більше пам'яті, ніж призначений масив. З іншого боку, хеш розростається динамічно і може набувати значно більших розмірів через необхідність відстежувати зіткнення значень.
Компроміс: Тепер, коли ви знаєте, що дешево, а що ні, і за яких обставин, ви зможете побачити компроміс. Фільтри цвітіння чудові, якщо ви хочете дуже швидко виявити, що значення було помічено раніше, але може жити з помилковими позитивами. З іншого боку, ви можете вибрати хеш-карту, якщо хочете гарантувати коректність ціною того, що не можете точно судити про час виконання, але ви можете приймати випадкові вироджені випадки, які можуть бути набагато повільнішими, ніж у середньому.
Так само, якщо ви перебуваєте в обмеженому середовищі пам'яті, ви можете віддати перевагу фільтрам цвітіння для гарантії їх використання.