Ръководство за техниката на сгъване в Java

1. Въведение

В този урок разглеждаме техниките за хеширане, използвани в различни структури от данни, които осигуряват постоянен времеви достъп до техните елементи.

Ние обсъждаме по-подробно така наречената техника на сгъване и даваме кратко въведение в техниките за среден квадрат и binning.

2. Общ преглед

Когато избираме структури от данни за съхраняване на обекти, едно от съображенията е дали трябва да имаме бърз достъп до тях.

Помощният пакет Java ни предлага доста много структури от данни за съхранение на нашите обекти. За повече информация относно структурите на данни вижте нашата страница за компилация на Java Collections, която съдържа ръководства за няколко от тях.

Както знаем, някои от тези структури от данни ни позволяват да извличаме техните елементи за постоянно време, независимо от броя на елементите, които те съдържат.

Вероятно най-простият е масивът. Всъщност ние имаме достъп до елементи в масива по техния индекс. Времето за достъп, естествено, не зависи от размера на масива. Всъщност зад сцената много структури от данни използват масиви.

Проблемът е, че индексите на масива трябва да са числови, докато ние често предпочитаме да манипулираме тези структури от данни с обекти.

За да се справи с този проблем, много структури от данни се опитват да присвоят числова стойност, която може да служи като индекс на масив на обекти. Ние наричаме тази стойност хеш стойност или просто хеш .

3. Хеширане

Хеширането е трансформация на обект в числова стойност . Функции, които изпълняват тези трансформации, се наричат хеш функции .

За по-голяма простота, нека да разгледаме хеш функции, които трансформират струни в индексите на масивите, което е, в цели числа от интервала [0, N] , с ограничен N .

Естествено, хеш функция се прилага към голямо разнообразие от струни . Следователно неговите „глобални“ свойства стават важни.

За съжаление не е възможно хеш функцията винаги да трансформира различни низове в различни числа .

Можем да се убедим доста лесно, че броят на низовете е много по-голям от броя на целите числа във всеки диапазон [0, N] . Следователно е неизбежно да има двойка неравностойни низове, за които хеш функцията генерира равни стойности. Това явление се нарича сблъсък .

Няма да се впускаме в инженерните подробности зад хеш функциите, но е ясно, че добрата хеш функция трябва да се опита да картографира еднообразно низовете, на които е дефинирана в числа.

Друго очевидно изискване е добрата хеш функция да бъде бърза. Ако отнема твърде много време за изчисляване на хеш стойност, тогава не можем да получим бърз достъп до елементи.

В този урок разглеждаме една от техниките, които се опитват да направят картографирането еднакво, като същевременно го поддържат бързо.

4. Техника на сгъване

Нашата цел е да намерим функция, която трансформира низовете в индекси на масиви. Само за да илюстрираме идеята, да предположим, че искаме този масив да има капацитет за 105 елемента и нека използваме низ Java като пример.

4.1. Описание

Нека започнем с преобразуване на символите на низа в числа. ASCII е добър кандидат за тази операция:

Сега подреждаме току-що получените числа в групи с някакъв размер. Като цяло избираме стойността на размера на групата въз основа на размера на нашия масив, който е 105. Тъй като числата, в които сме преобразували символите, съдържат от две до три цифри, без загуба на общ характер, можем да зададем размера на групата на две:

Следващата стъпка е да обедините числата във всяка група, като че ли са низове, и да намерите тяхната сума:

Сега трябва да направим последната стъпка. Нека проверим дали числото 348933 може да служи като индекс на нашия масив с размер 105. Естествено, той надвишава максимално допустимата стойност 99999. Може лесно да преодолеем този проблем, като приложим модулния оператор, за да намерим крайния резултат:

348933 % 10000 = 48933

4.2. Заключителни бележки

Виждаме, че алгоритъмът не включва отнемащи време операции и следователно е доста бърз. Всеки знак от входния низ допринася за крайния резултат. Този факт определено помага да се намалят сблъсъците, но не и да се избегнат напълно.

Например, ако искахме да пропуснем сгъването и приложихме модулния оператор директно към преобразувания ASCII входен низ (игнорирайки проблема с препълването)

749711897321089711010311797103101 % 100000 = 3101

тогава такава хеш функция ще генерира една и съща стойност за всички низове, които имат същите последните два знака като нашия входен низ: a ge , p age , lar ge и т.н.

От описанието на алгоритъма можем лесно да видим, че той не е свободен от сблъсъци. Например алгоритъмът произвежда една и съща хеш стойност за езика Java и езиковите низове vaJa .

5. Други техники

Техниката на сгъване е доста разпространена, но не е единствената. Понякога техниките за подреждане или средно квадратче също могат да бъдат полезни.

Ние илюстрираме идеята им, като не използваме низове, а числа (да предположим, че вече сме трансформирали по някакъв начин низовете в числа). Няма да обсъждаме техните предимства и слабости, но може да си направите мнение, след като видите алгоритмите.

5.1. Техника на смесване

Да предположим, че имаме 100 цели числа и искаме нашата хеш функция да ги преобразува в масив от 10 елемента. Тогава можем просто да подредим тези 100 цели числа в десет групи по такъв начин, че първите десет цели числа да попаднат в първия контейнер, вторите десет цели числа да попаднат във втория контейнер и т.н.:

5.2. Техника на средния квадрат

Този алгоритъм е предложен от Джон фон Нойман и той ни позволява да генерираме псевдослучайни числа, започвайки от дадено число.

Нека го илюстрираме на конкретен пример. Да предположим, че имаме четирицифрено число 1111 . Според алгоритъма го квадратираме, като по този начин получаваме 1234321 . Сега извличаме четири цифри от средата, например 2343 . Алгоритъмът ни позволява да повторим този процес, докато не сме доволни от резултата.

6. Заключение

В този урок разгледахме няколко техники за хеширане. Описахме подробно техниката на сгъване и дадохме светкавично описание на начина, по който могат да бъдат постигнати binning и mid-square.

Както винаги, може да намерим съответните кодови фрагменти в нашето хранилище GitHub.