Якщо відра занадто повні, то нам доведеться переглядати
дуже довгий зв'язаний список.
І це начебто переможе питання.
Тож ось приклад, коли у мене чотири відра.
У мене в моєму HashSet поки що є слон і борсук.
Це досить гарна ситуація, правда?
Кожен елемент має нуль або один елемент.
Тепер ми помістили ще два елементи в наш HashSet.
buckets elements
------- -------
0 elephant
1 otter
2 badger
3 cat
Це теж не дуже погано.
У кожному відрі є лише один елемент. Тож якщо я хочу знати, чи містить це панда?
Я дуже швидко можу подивитися на відро №1, і це не так
там і
Я знав, що його немає в нашій колекції.
Якщо я хочу знати, чи містить він кішку, я дивлюся на відро
номер 3,
Я знаходжу кота, я дуже швидко знаю, чи є він у нас
колекція.
Що робити, якщо я додаю коалу, ну це не так вже й погано.
buckets elements
------- -------
0 elephant
1 otter -> koala
2 badger
3 cat
Можливо, тепер замість того, щоб у відрі №1 лише дивитись
один елемент,
Мені потрібно подивитися на два.
Але принаймні мені не треба дивитися на слона, борсука і
кіт.
Якщо я знову шукаю панду, вона може бути лише у відрі
№ 1 і
Мені не треба дивитись ні на що інше, ніж видру і
коала.
Але тепер я помістив алігатор у відро № 1 і ви можете
побачимо, можливо, куди це йде.
Що якщо відро № 1 продовжує збільшуватися і збільшуватися
Більше, тоді я в основному повинен переглядати все
ті елементи, які потрібно знайти
те, що повинно бути у відрі №1.
buckets elements
------- -------
0 elephant
1 otter -> koala ->alligator
2 badger
3 cat
Якщо я почну додавати рядки до інших відер,
правильно, проблема просто стає все більшою і більшою
одне відро.
Як ми не можемо наші відра занадто заповнитись?
Рішення тут таке
"the HashSet can automatically
resize the number of buckets."
Там HashSet розуміє, що відра отримують
занадто повний.
Це втрачає перевагу цього всього одного пошуку
елементів.
І це просто створить більше відра (як правило, вдвічі) та
потім помістіть елементи у правильне відро.
Отже, ось наша основна реалізація HashSet з окремими
прикування. Тепер я збираюся створити "саморозмінювану HashSet".
Цей HashSet зрозуміє, що це відра
занадто повно і
їй потрібно більше відра.
loadFactor - ще одне поле в нашому класі HashSet.
loadFactor являє собою середню кількість елементів на
відро,
над яким ми хочемо змінити розмір.
loadFactor - це баланс між простором і часом.
Якщо відра будуть занадто повними, ми змінимо розмір.
На це потрібен час, звичайно, але
це може заощадити нам час в дорозі, якщо відра є
трохи більше порожнього.
Подивимось приклад.
Ось HashSet, ми до цього часу додали чотири елементи.
Слон, собака, кішка і риба.
buckets elements
------- -------
0
1 elephant
2 cat ->dog
3 fish
4
5
У цей момент я вирішив, що loadFactor,
поріг,
середня кількість елементів на відро, що я в порядку
з, дорівнює 0,75.
Кількість відра - це відра. Довжина, яка дорівнює 6, і
на даний момент наш HashSet має чотири елементи, так що
поточний розмір - 4.
Ми змінимо розмір нашого HashSet, тобто додамо більше відра,
коли середня кількість елементів на відро перевищує
фактор навантаження
Це коли поточний розмір, поділений на buckets.length is
більше, ніж навантаженняFactor.
У цей момент середня кількість елементів на відро
це 4 ділиться на 6.
4 елементи, 6 відра, це 0,67.
Це менше порогу, який я встановив 0,75, тому ми
добре.
Нам не потрібно змінювати розмір.
Але тепер скажімо, ми додаємо дровочком.
buckets elements
------- -------
0
1 elephant
2 woodchuck-> cat ->dog
3 fish
4
5
Вудхук опинився б у відрі №3.
У цей момент, currentSize дорівнює 5.
А тепер середня кількість елементів на відро
- поточний розмір, поділений на buckets.length.
Це 5 елементів, розділених на 6 відер, це 0,83.
І це перевищує коефіцієнт навантаження, який становив 0,75.
Щоб вирішити цю проблему, щоб зробити
відра, можливо, небагато
більш порожнім, щоб такі операції, як визначення того, чи є
відро містить
елемент буде трохи менш складним, я хочу змінити розмір
мій HashSet
Змінення розміру HashSet здійснює два кроки.
Спочатку я подвою кількість відра, у мене було 6 відра,
зараз у мене буде 12 відра.
Зауважимо, що loadFactor, який я встановив у 0,75, залишається таким же.
Але кількість відра, що змінилися, становить 12,
кількість елементів, що залишилися однаковими, дорівнює 5.
5 ділиться на 12 - це приблизно 0,42, це добре під нашим
loadFactor,
тож зараз у нас все гаразд.
Але ми не закінчили, тому що деякі з цих елементів є
неправильне відро зараз.
Наприклад, слон.
Слон був у відрі №2, оскільки кількість
символи в слоні
було 8.
У нас 6 відер, 8 мінус 6 - це 2.
Ось чому воно і закінчилося у №2.
Але тепер, коли у нас є 12 відра, 8 мод 12 - це 8, так
слон вже не належить до відра №2.
Слон належить до відра № 8.
А що з дрочком?
Вудчук став тим, хто розпочав всю цю проблему.
Вудхук опинився у відрі №3.
Тому що 9 мод 6 - це 3.
Але зараз ми робимо 9 мод 12.
9 mod 12 - 9, woodchuck переходить до відра № 9.
І ви бачите перевагу всього цього.
Зараз у відрі №3 є лише два елементи, тоді як до цього було 3.
Отже, ось наш код,
де у нас був наш HashSet з окремим ланцюжком
не робив жодних змін.
Тепер ось нова реалізація, де ми використовуємо розмір розміру.
Більшість цього коду однакові,
ми все ще будемо визначати, чи містить він
значення вже.
Якщо це не так, то ми визначимо, яке це відро
повинні зайти в і
потім додайте його у це відро, додайте до цього LinkedList.
Але тепер ми збільшуємо поле currentSize.
currentSize - це поле, яке відстежувало число
елементів у нашому HashSet.
Ми збільшимо його, а потім будемо шукати
при середньому навантаженні,
середня кількість елементів на відро.
Ми зробимо цей відділ тут.
Ми повинні зробити трохи кастинг тут, щоб переконатися
що ми отримуємо подвійний.
А потім ми порівняємо це середнє навантаження з полем
що я встановив як
0,75, коли я створив цей HashSet, наприклад, який був
фактор навантаження
Якщо середнє навантаження більше, ніж коефіцієнт навантаження,
це означає, що на відро занадто багато елементів
в середньому, і мені потрібно знову вставити.
Тож ось наша реалізація методу для повторного вставки
всі елементи.
По-перше, я створять локальну змінну під назвою oldBuckets.
Що стосується відра, як вони зараз стоять
перш ніж я почну все змінювати розмір.
Примітка. Я ще не створюю новий масив пов'язаних списків.
Я просто перейменувавши відра як старі Кошики.
Тепер пам’ятайте, відра були полем у нашому класі, я йду
тепер створити новий масив
пов'язаних списків, але в них буде вдвічі більше елементів
як це було вперше.
Тепер мені потрібно зробити перевстановлення,
Я збираюся переглядати всі старі відра.
Кожен елемент у OldBuckets є LinkedList рядків
це відро.
Я пройду це відро і отримаю кожен елемент у цьому
відро.
А тепер я знову вставлю його в нові Квіти.
Я отримаю його хеш-код.
Я розберуся, який це індекс.
І тепер я отримую нове відро, новий LinkedList від
струни і
Я додам його до того нового відра.
Таким чином, для резюме, HashSets, як ми бачили, є масивами Linked
Списки або відра.
HashSet, що змінює розмір, може реалізувати, використовуючи деяке співвідношення або
capacity = N/0.75
щоб уникнути Rehashing, але моя початкова ідея була просто встановитиload factor = 1
. Чи будуть недоліки такого підходу? Чому впливає фактор навантаженняget()
таput()
витрати на експлуатацію?