Hash Tables werden in verschiedenen Programmiersprachen unterschiedlich bezeichnet, sind aber ein und die selbe Sache. In Java werden Hash Tables "HashMaps" genannt, in JavaScript "Objects" und in Python oder C# "Dictionaries". Die HashTable ordnet einem Schlüssel Werte zu (key-value-pairs). Jeder Key ist einzigartig und kann nur einem Value zugeordnet werden. Deshalb ist sie auch so super schnell in LookUps und wir können sie nutzen, um unsere Algorithmen zu optimieren.
Hash Tables sind unglaublich mächtig, weil sie sehr schnelle Einfüge-,
Such- und Entfernungszeiten haben.
Search O(1)
Insert O(1)
Delete O(1)
Deshalb sollte man in der Praxis auf der Suche nach einer Lösung für ein Problem direkt und als Allererstes an sie denken.
Sie werden verwendet für Features wie:
Beim Mappen kann es zu Kollisionen kommen. Das passiert, wenn zwei Keys denselben hash-value generiert haben. Beide Keys wollen also bspw. ihre Werte bei Adresse 10 lagern und kolldieren deswegen. Es gibt 2 Wege, damit umzugehen:
CHAINING:
Jede Zelle eines Arrays zeigt auf eine LinkedList. Die Werte werden nicht im Array sondern in der LinkedList gelagert. Wenn eine Kollision aufftritt, wird das neue Element einfach an die LinkedList angehängt.
OPEN ADDRESSING:
Eine andere Lösung ist es, einen anderen Slot zu finden, um den zweiten Wert zu lagern. Es gibt unterschiedliche Algorithmen dazu.
Hier kommt der Begriff "Probing" in Spiel, welcher das Suchen nach freien Slots beschreibt. Es werden unterschiedliche Arten des "Probing" eingesetzt (Linear Probing, Quadratic Probing, Double Hashing).
Lineares Probing ist z.B., wenn wir mit dem aktuellen (besetzten) Slot starten und uns immer weiter entlang der HashTable nach unten bewegen, bis ein freier Slot gefunden wurde, wo der Wert eingesetzt werden kann.
Linear Probing: (hash1+ i) % table_size
Quadratic Probing: (hash1+ i^2) % table_size
Double Hash: (hash1+ i* hash2) % table_size
Es gibt verschiedene Map-Typen in Java, die wie folgt beschrieben werden:
HashMap
Es handelt sich um eine ungeordnete und unsortierte Map-basierte
Sammlungsklasse zum Speichern von Key-Value-Pairs. Sie ist eine
gute Wahl, wenn keine Reihenfolge benötigt wird, denn sie behält keine
Einfügereihenfolge bei. Eine HashMap lässt einen NULL-Schlüssel und mehrere NULL-Werte zu, überschreibt aber gleiche Key-Value-Pairs. Es wird via Iterator über die Werte iteriert.
HashTable
Die HashTable ist hingegen ein Array einer Liste, wobei jede Liste als
Bucket bezeichnet wird. In einer HashTable enthaltene Values sind
eindeutig und hängen von ihrem Key ab. Sie erlaubt keine
Null-Schlüssel oder -Werte und hat Methoden, die synchronisiert
werden. Da sie die Thread-Sicherheit ermöglicht, ist die Leistung
langsam. Es wird via Enumerator über die Werte iteriert.
LinkedHashMap
Sie ist langsamer als eine HashMap, behält aber die Einfügereihenfolge
bei und hat eine schnellere Iteration.
TreeMap
Eine sortierte Map, die das Erstellen einer Sortierreihenfolge
mithilfe eines Constructors unterstützt.
Sets
Ein Set erlaubt keine Key-Duplikate und ist deshalb sehr nützlich. Wenn wir z.B. eine Liste voller Duplikate haben, müssen wir diese einfach in ein Set setzen und erhalten eine Liste ohne Duplikate.