Die Geschichte, dass Hash-Tabellen amortisiert werden ist eine Lüge, eine übermäßige Vereinfachung. Θ(1)
Dies gilt nur, wenn:
- Die Menge der zu hashenden Daten pro Element im Vergleich zur Anzahl der K eys trivial ist und die Geschwindigkeit des Hashing eines K ey schnell ist - .
- Die Anzahl der C ollisions ist klein - c .
- Wir nicht berücksichtigen Zeit benötigt , um R die Hash - Tabelle ESIZE - r .k
c
r
Große Zeichenfolgen für Hash
Wenn die erste Annahme falsch ist, steigt die Laufzeit auf .
Dies gilt definitiv für große Saiten, aber für große Saiten hätte ein einfacher Vergleich auch eine Laufzeit von Θ ( k ) . Ein Hash ist also nicht asymptotisch langsamer, obwohl das Hashing immer langsamer ist als ein einfacher Vergleich, da der Vergleich ein frühes Opt-out hat, also O ( 1 ) , Ω ( k ) und das Hashing immer den vollen String O ( k ) hashen muss. Ω ( k )Θ(k)
Θ(k)O(1)Ω(k)O(k)Ω(k).
Beachten Sie, dass Ganzzahlen sehr langsam wachsen. 8 Bytes können Werte bis zu speichern ; 8 Bytes sind eine triviale Menge an Hash.
Wenn Sie Bigint speichern möchten, stellen Sie sich diese einfach als Zeichenfolgen vor. 1018
Langsamer Hash-Algorithmus
Wenn der Hashing-Betrag im Vergleich zur Speicherung der Daten nicht trivial ist, wird die Annahme offensichtlich unhaltbar.
Sofern kein kryptografischer Hash verwendet wird, sollte dies kein Problem sein.Θ(1)
Entscheidend ist , dass > > k . Solange dies gilt, ist Θ ( 1 ) eine faire Aussage.n >> kΘ(1)
Viele Kollisionen
Wenn die Hashing-Funktion schlecht ist oder die Hash-Tabelle klein ist oder die Größe der Hash-Tabelle unangenehm ist, treten häufig Kollisionen auf und die Laufzeit geht auf .
Die Hashing-Funktion sollte so gewählt werden, dass Kollisionen selten sind und dennoch so schnell wie möglich. Wenn Sie Zweifel haben, entscheiden Sie sich für weniger Kollisionen auf Kosten eines langsameren Hashing.
Als Faustregel gilt, dass die Hashing-Tabelle immer zu weniger als 75% gefüllt sein sollte.
Und die Größe der Hashing-Tabelle sollte keine Korrelation mit der Hashing-Funktion haben.
Oft ist die Größe der Hashing-Tabelle (relativ) prim. O(log(n))
Ändern der Größe der Hash-Tabelle
Da eine fast vollständige Hash-Tabelle zu viele Kollisionen verursacht und eine große (leere) Hash-Tabelle Platzverschwendung darstellt, können Sie bei vielen Implementierungen die Hash-Tabelle nach Bedarf vergrößern (und verkleinern!).
Das Erweitern einer Tabelle kann eine vollständige Kopie aller Elemente (und möglicherweise eine Umbildung) umfassen, da der Speicher aus Leistungsgründen kontinuierlich sein muss.
Nur in pathologischen Fällen ist die Größenänderung der Hash-Tabelle ein Problem, sodass die (kostspieligen, aber seltenen) Größenänderungen über viele Aufrufe hinweg abgeschrieben werden.
Laufzeit
Die tatsächliche Laufzeit einer Hash-Tabelle ist also .
Es wird angenommen, dass jedes von k , c , r im Durchschnitt eine (kleine) Konstante in der amortisierten Laufzeit ist, und daher sagen wir, dass Θ ( 1 ) eine faire Aussage ist. Θ(kcr)
kcrΘ(1)
Um auf Ihre Fragen zurückzukommen
Bitte entschuldigen Sie die Umschreibung. Ich habe versucht, verschiedene Bedeutungen zu extrahieren. Sie können gerne Kommentare abgeben, wenn ich einige verpasst habe
Sie scheinen besorgt über die Länge der Ausgabe der Hash-Funktion zu sein. Nennen wir dies ( n wird im Allgemeinen als die Anzahl der zu hashenden Elemente angesehen). m ist l o g ( n ), da m einen Eintrag in der Hash-Tabelle eindeutig identifizieren muss.
Dies bedeutet, dass m sehr langsam wächst. Bei 64 Bit nimmt die Anzahl der Hash-Tabelleneinträge einen beträchtlichen Teil des weltweit verfügbaren RAM ein. Mit 128 Bit wird der verfügbare Festplattenspeicher auf dem Planeten Erde weit überschritten.
Das Erstellen eines 128-Bit-Hashs ist nicht viel schwieriger als das Erstellen eines 32-Bit-Hashs. Nein , die Zeit zum Erstellen eines Hashs ist nicht O (mnmlog(n)
(oder O ( l o g ( n ) ), wenn Sie so wollen). O(m)O(log(n))
Die Hash-Funktion, die Bits des Elements durchläuft , benötigt Θ ( l o g ( n ) ) Zeit. log(n)Θ(log(n))
Die Hash-Funktion durchläuft jedoch keine Bits von Elementen.
Pro Punkt (!!) geht es nur durch Daten.
Auch die Länge der Eingabe (k) hat keine Beziehung zur Anzahl der Elemente. Dies ist wichtig, da einige Nicht-Hashing-Algorithmen viele Elemente in der Sammlung untersuchen müssen, um ein (nicht) übereinstimmendes Element zu finden.
In der Hash-Tabelle werden durchschnittlich nur 1 oder 2 Vergleiche pro betrachtetem Element durchgeführt, bevor eine Schlussfolgerung gezogen wird. O ( k )log(n)
O(k)
Warum sind Hash-Tabellen zum Speichern von Elementen variabler Länge effizient?
Da unabhängig von der Länge der Eingabe ( ) die Länge der Ausgabe ( ) immer gleich ist, sind Kollisionen selten und die Suchzeit konstant.
Wenn jedoch die Schlüssellänge Vergleich zur Anzahl der Elemente in der Hash-Tabelle ( ) groß wird, ändert sich die Geschichte ...m k nkm
kn
Warum können Hash-Tabellen große Zeichenfolgen effizient speichern?
Hash-Tabellen sind für sehr große Zeichenfolgen nicht sehr effizient .
Wenn (dh die Größe der Eingabe ist im Vergleich zur Anzahl der Elemente in der Hash-Tabelle ziemlich groß), können wir nicht mehr sagen, dass der Hash eine konstante Laufzeit hat, sondern auf eine Laufzeit von wechseln muss allem, weil es kein frühes Aus gibt. Sie müssen den vollständigen Schlüssel hashen. Wenn Sie nur eine begrenzte Anzahl von Elementen speichern, ist es möglicherweise viel besser, einen sortierten Speicher zu verwenden, da Sie beim Vergleich von deaktivieren können, sobald ein Unterschied festgestellt wird. n > > k Θ ( k ) , k 1 ≠ k 2not n>>kΘ(k)k1 ≠ k2
Wenn Sie jedoch Ihre Daten kennen, können Sie festlegen, dass nicht der vollständige Schlüssel, sondern nur der (bekannte oder angenommene) flüchtige Teil davon gehasht wird. Dabei wird die Eigenschaft wiederhergestellt, während die Kollisionen in Schach gehalten werden. Θ(1)
Versteckte Konstanten
Wie jeder wissen sollte, bedeutet einfach, dass die Zeit pro verarbeitetem Element eine Konstante ist. Diese Konstante ist für das Hashing viel größer als für den einfachen Vergleich.
Bei kleinen Tabellen ist eine binäre Suche schneller als eine Hash-Suche, da beispielsweise 10 binäre Vergleiche sehr wohl schneller sind als ein einzelner Hash.
Für kleine Datensätze sollten Alternativen zu Hash-Tabellen in Betracht gezogen werden.
Bei großen Datenmengen leuchten Hash-Tabellen wirklich.Θ(1)