Hashtabellen
Ist 47 in einer Tabelle mit 7 Buckets gespeichert, geht der Computer direkt zu Bucket 47 mod 7 = 5, statt die ganze Tabelle zu durchsuchen.
Aus einem Schlüssel eine Position machen
Bisher hieß einen Wert finden: suchen, bis zu n Schritte in einem unsortierten Array oder einer verketteten Liste. Arrays erreichen aber jede Position in einem Schritt. Was, wenn der Schlüssel selbst die Position verriete? Wären deine Schlüssel kleine ganze Zahlen, etwa Schülernummern von 0 bis 99, könntest du ein Array mit 100 Zellen führen und Schüler k in Zelle k speichern. Die MIT-Unterlagen nennen das ein Direktzugriffs-Array (direct access array). Es scheitert, wenn die möglichen Schlüssel riesig sind, wie Telefonnummern oder Wörter, weil man sich nicht für jeden möglichen Schlüssel eine Zelle leisten kann.
Eine Hashfunktion löst das, indem sie jeden Schlüssel in einen kleinen Bereich von Positionen presst, 0 bis m − 1. Eine einfache für ganze Zahlen ist h(k) = k mod m, der Rest beim Teilen durch m. Das Array mit m Zellen ist die Hashtabelle, und ihre Zellen heißen oft Buckets (Behälter). Um 47 mit m = 7 zu speichern, rechne 47 mod 7 = 5 und leg den Wert in Bucket 5. Um 47 später zu finden, rechne dasselbe und schau nur in Bucket 5.
Kollisionen und Verkettung
Es gibt ein Problem. Bei 7 Buckets und mehr als 7 möglichen Schlüsseln müssen sich manche Schlüssel einen Bucket teilen: 12, 33 und 47 haben alle den Rest 5. Das nennt man Kollision, und die MIT-Unterlagen weisen darauf hin, dass sie sich nach dem Schubfachprinzip nicht vermeiden lässt. Das übliche Mittel ist Verkettung (Chaining): Jeder Bucket hält eine kleine Liste, eine Kette, mit allen Schlüsseln, die dort gelandet sind. 47 zu finden, kostet dann 1 Schritt für den Hash plus einen Vergleich für jeden geprüften Schlüssel in Kette 5. Stehen 12 und 33 davor, sind das 1 + 3 = 4 Schritte.
Wie lang sind die Ketten? Verteilen sich die Schlüssel gleichmäßig, enthält jede Kette etwa n/m Schlüssel, eine Zahl, die man Belegungsfaktor (load factor) nennt. Hält man m ungefähr so groß wie n, bleiben die Ketten kurz, und Finden, Einfügen und Löschen kosten im Mittel eine konstante Zahl von Schritten. Die Gefahr ist eine schlechte Verteilung. Landet jeder Schlüssel im selben Bucket, enthält eine Kette alle n Schlüssel, und die Tabelle ist nicht besser als eine verkettete Liste. Stell im Labor 7 Buckets ein und füg 14, 21 und 28 ein: Alle landen in Bucket 0.
Zum Drehen ziehen. Zum Zoomen scrollen oder mit zwei Fingern ziehen.
Hashtabellen in JavaScript
Eine Hashtabelle schreibst du selten selbst, weil JavaScript Map und Set hat. Die ECMAScript-Spezifikation sagt, sie müssten „entweder mit Hashtabellen oder mit anderen Mechanismen umgesetzt werden, die im Mittel Zugriffszeiten bieten, die sublinear in der Zahl der Elemente sind“. Mit anderen Worten: map.get(key) und set.has(x) müssen schneller sein, als die ganze Sammlung zu durchsuchen. MDN ergänzt, dass eine Map die Schlüssel in Einfügereihenfolge hält und, anders als ein normales Objekt, keine Standardschlüssel enthält, die mit deinen kollidieren könnten.
const price = new Map();
price.set("apple", 1.2);
price.set("bread", 2.5);
console.log(price.get("bread")); // 2.5, ohne die Liste zu durchsuchen
console.log(price.has("milk")); // false
const seen = new Set([4, 8, 15]);
console.log(seen.has(8)); // true| Hashfunktion | Macht aus einem Schlüssel eine Bucket-Nummer von 0 bis m − 1, zum Beispiel k mod m. |
| Kollision | Zwei verschiedene Schlüssel bekommen denselben Bucket. Unvermeidbar, wenn es mehr Schlüssel als Buckets gibt. |
| Verkettung (Chaining) | Jeder Bucket führt eine Liste aller Schlüssel, die dort gelandet sind. |
| Belegungsfaktor | n/m, die durchschnittliche Kettenlänge. |
| Map und Set | Die eingebauten Schlüssel-Sammlungen von JavaScript, die im Mittel schneller als linear sein müssen. |
- In welchen Bucket kommt 47 mit h(k) = k mod 7?
- Die Tabelle enthält 12, 25, 33, 47, 70 (in dieser Reihenfolge eingefügt) mit m = 7. Wie viele Schritte kostet das Finden von 47 (1 für den Hash plus verglichene Schlüssel)?
- Dieselbe Tabelle: Wie viele Schritte, um 12 zu finden?
- Dieselbe Tabelle: 19 ist nicht gespeichert. Wie viele Schritte kostet die Suche nach 19?
- Dieselbe Tabelle: Wie groß ist der Belegungsfaktor n/m? (zwei Nachkommastellen)
- Was ist eine Kollision?
- Ein Schlüssel, der zu groß ist
- Zwei verschiedene Schlüssel landen im selben Bucket
- Ein Schlüssel wird zweimal gelöscht
- Eine Tabelle ohne Schlüssel
- Warum kann keine Hashfunktion Kollisionen vermeiden, wenn es mehr mögliche Schlüssel als Buckets gibt?
- Computer runden Zahlen
- Das Schubfachprinzip
- Schlüssel sind immer gerade
- Ketten sind zu kurz
- Wie verhält sich das Finden eines Schlüssels, wenn jeder Schlüssel im selben Bucket landet?
- Weiterhin 1 Schritt
- Wie die Suche in einer verketteten Liste mit n Schlüsseln
- Es wird unmöglich
- Wie die binäre Suche
- Was verlangt die ECMAScript-Spezifikation von den Zugriffszeiten einer Map?
- Genau 1 Schritt
- Im Mittel sublinear in der Zahl der Elemente
- Θ(n log n)
- Nichts
- Luhns Hash von 1953 addierte benachbarte Ziffernpaare und behielt von jeder Summe die letzte Ziffer. Was wird aus 31415926?
- Eine Hashfunktion macht aus einem Schlüssel eine Bucket-Nummer; k mod m ist eine einfache.
- Kollisionen sind unvermeidbar; Verkettung hält in jedem Bucket eine Liste.
- Bleibt der Belegungsfaktor n/m klein, kosten Finden, Einfügen und Löschen im Mittel konstant viele Schritte.
- Map und Set in JavaScript müssen im Mittel schneller als linear sein.
Quellen zu diesem Kurs (11)
- MIT OpenCourseWare 6.006 Introduction to Algorithms, Spring 2020 (Demaine, Ku, Solomon)
- lecture notes 2 Data Structures (interface vs data structure, Sequence and Set interfaces, stack = insert_last/delete_last, queue = insert_last/delete_first, array, linked list, dynamic array, amortized Θ(1) append)
- 4 Hashing (chaining, pigeonhole collisions, chain length n/m)
- 6 Binary Trees Part 1 (height, traversal order, O(h) operations) and 7 Binary Trees Part 2: AVL (Adelson-Velsky and Landis, 1962) at ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/pages/lecture-notes
- MDN Web Docs, Array.prototype.shift (shifts all values left by 1)
- Array.prototype.unshift, Map (insertion order, Map vs Object, spec requires sublinear average access) and Set (developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects)
- ECMAScript 2025 Language Specification (tc39.es/ecma262)
- 24.1 Map Objects and 24.2 Set Objects ("must be implemented using either hash tables or other mechanisms that, on average, provide access times that are sublinear on the number of elements")
- Array.prototype.shift steps (Repeat, while k < len: move element k to k - 1)
- D. E. Knuth, The Art of Computer Programming vol. 3 (2nd ed. 1998) section 6.4 History (H. P. Luhn, IBM internal memorandum January 1953, hashing with chaining; digit pairs added mod 10, 31415926 -> 4548) via gwern.net copy, and IEEE Spectrum, "Hans Peter Luhn and the Birth of the Hashing Algorithm" (2018)
- "A brief history of the stack", SIGCIS (sigcis.org/files/A brief history.pdf: Bauer and Samelson applied for the patent in 1957, US 3,047,228 granted July 31, 1962; IPL list processing by Newell, Simon and Shaw at RAND 1956) and Wikipedia, Information Processing Language (Newell, Shaw, Simon, RAND and Carnegie Institute of Technology, about 1956).
Abgerufen: 2026-10-18