Hash-Funktion
A Hash-Funktion ist jeder Funktion Das kann verwendet werden, um abzubilden Daten von willkürlicher Größe zu Werten mit fester Größe.[1] Die von einer Hash -Funktion zurückgegebenen Werte werden aufgerufen Hash -Werte, Hash -Codes, Verdauung, oder einfach Hashes. Die Werte werden normalerweise verwendet, um eine Tabelle fester Größe zu indexieren, die als a Hash-tabelle. Die Verwendung einer Hash -Funktion zum Index einer Hash -Tabelle wird genannt Hashing oder Streuspeicheradressierung.
Hash -Funktionen und ihre zugehörigen Hash -Tabellen werden in Datenspeichern und Abrufanwendungen verwendet, um auf Daten in einer kleinen und nahezu konstanten Zeit pro Abruf zugreifen zu können. Sie benötigen eine Menge Speicherplatz nur fraktionell größer als der Gesamtraum für die Daten oder Aufzeichnungen selbst. Hashing ist eine rechnerische und speicherplatzeffiziente Form des Datenzugriffs, die die nicht konstante Zugriffszeit der geordneten und ungeordneten Listen und strukturierten Bäume sowie die häufig exponentiellen Speicheranforderungen für den direkten Zugriff von Zustandsräumen großer oder variabler Länge vermeidet.
Die Verwendung von Hash-Funktionen basiert auf statistischen Eigenschaften der Schlüssel- und Funktionsinteraktion: Das schlechteste Verhalten ist unerträglich schlecht mit einer verschwindend geringen Wahrscheinlichkeit, und durchschnittliches Verhalten kann nahezu optimal sein (minimal (minimal Kollision).[2]
Hash -Funktionen beziehen sich auf (und oft verwechselt mit) Überprüfungen, Ziffern überprüfen, Fingerabdrücke, Verlustige Komprimierung, Randomisierungsfunktionen, Fehlerkorrigierende Codes, und Chiffren. Obwohl sich die Konzepte in gewissem Maße überschneiden, hat jeder seine eigenen Verwendungen und Anforderungen und wird unterschiedlich entworfen und optimiert. Die Hash -Funktion unterscheidet sich von diesen Konzepten hauptsächlich in Bezug auf Datenintegrität.
Überblick
Eine Hash -Funktion nimmt eine Eingabe als Schlüssel an, die einem Datum oder Datensatz zugeordnet und verwendet wird, um sie für die Datenspeicherung und Abrufanwendung zu identifizieren. Die Schlüssel können wie eine Ganzzahl oder variable Länge wie ein Name festgelegt sein. In einigen Fällen ist der Schlüssel das Datum selbst. Die Ausgabe ist ein Hash -Code, mit dem eine Hash -Tabelle die Daten oder Aufzeichnungen oder Zeiger auf sie indexiert wird.
Eine Hash -Funktion kann als drei Funktionen in Betracht gezogen werden:
- Tasten mit variabler Länge in feste Länge (normalerweise maschinelle Wortlänge oder weniger) Werte umwandeln, indem sie sie mit Wörtern oder anderen Einheiten mit einem Paritätsvorrangbetreiber wie Add oder XOR falten.
- Schreiben Sie die Tastenbits so, dass die resultierenden Werte gleichmäßig über den Schlüsselraum verteilt sind.
- Zeichnen Sie die Schlüsselwerte in diejenigen ab, die weniger als oder gleich der Größe der Tabelle sind
Eine gute Hash -Funktion erfüllt zwei grundlegende Eigenschaften: 1) Sie sollte sehr schnell berechnen. 2) Es sollte die Duplikation von Ausgangswerten (Kollisionen) minimieren. Hash -Funktionen beruhen darauf, günstige Wahrscheinlichkeitsverteilungen für ihre Wirksamkeit zu erzeugen und die Zugriffszeit auf nahezu konstante zu verkürzen. Hochtabelle Belastungsfaktoren, pathologisch Schlüsselsätze und schlecht gestaltete Hash -Funktionen können dazu führen, dass sich die Zugriffszeiten in der Anzahl der Elemente in der Tabelle linear nähern. Hash-Funktionen können so konzipiert werden, dass sie die beste Leistung der Worst-Case-Leistung verleihen.[Anmerkungen 1] Gute Leistung unter hohen Tabellenladungsfaktoren und in besonderen Fällen perfekte (kollisionslose) Zuordnung von Schlüssel in Hash -Codes. Die Implementierung basiert auf Paritätsvorrangbitoperationen (XOR und ADD), Multiplizieren oder Division. Eine notwendige Ergänzung zur Hash-Funktion ist eine Kollisionsauflösungsmethode, die eine Hilfsdatenstruktur wie verwendet verlinkte Listen, oder systematische Prüfung der Tabelle, um einen leeren Steckplatz zu finden.
Hash -Tische
Hash -Funktionen werden in Verbindung mit verwendet Hash -Tische zum Speichern und Abrufen von Datenelementen oder Datensätzen. Die Hash -Funktion übersetzt den Schlüssel, der jedem Datum oder Datensatz zu einem Hash -Code zugeordnet ist, der zum Index der Hash -Tabelle verwendet wird. Wenn der Tabelle ein Element hinzugefügt werden soll, kann der Hash -Code einen leeren Steckplatz (auch als Eimer bezeichnet) indexieren. In diesem Fall wird das Element dort zur Tabelle hinzugefügt. Wenn der Hash -Code einen vollständigen Steckplatz indexiert, ist eine Art Kollisionsauflösung erforderlich: Das neue Element kann weggelassen werden (nicht zur Tabelle hinzugefügt) oder ersetzen Sie das alte Element oder kann an einem anderen Ort nach der Tabelle hinzugefügt werden ein angegebenes Verfahren. Dieses Verfahren hängt von der Struktur der Hash -Tabelle ab: in gekettetes HashingJeder Steckplatz ist der Kopf einer verknüpften Liste oder Kette, und Elemente, die am Schlitz kollidieren, werden der Kette hinzugefügt. Ketten können in zufälliger Reihenfolge gehalten und linear oder in serieller Reihenfolge oder als Selbstbestellung durch Frequenz durchsucht werden, um den Zugriff zu beschleunigen. Im Offene Adresse Hashing, die Tabelle wird ab dem besetzten Steckplatz auf eine bestimmte Weise untersucht, normalerweise durch lineare Untersuchung, Quadratische Prüfung, oder Double Hashing Bis ein offener Schlitz befindet oder der gesamte Tisch untersucht wird (Überlauf). Die Suche nach dem Element folgt dem gleichen Verfahren, bis sich das Element befindet, ein offener Steckplatz gefunden wurde oder die gesamte Tabelle durchsucht wurde (Element nicht in der Tabelle).
Spezialisierte Verwendungszwecke
Hash -Funktionen werden auch zum Erstellen verwendet Caches für große Datensätze, die in langsamen Medien gespeichert sind. Ein Cache ist im Allgemeinen einfacher als eine Hashed -Suchtabelle, da jede Kollision gelöst werden kann, indem die älteren der beiden kollidierenden Elemente abgeworfen oder zurückgeschrieben werden.[3]
Hash -Funktionen sind ein wesentlicher Bestandteil der Blütefilter, ein platzeffizienter probabilistisch Datenstruktur das wird verwendet, um zu testen, ob eine Element ist ein Mitglied von a einstellen.
Ein Sonderfall von Hashing ist als bekannt als Geometrisches Hashing oder Die Gittermethode. In diesen Anwendungen ist der Satz aller Eingänge eine Art von Art von metrischer Raumund die Hashing -Funktion kann als interpretiert werden Trennwand von diesem Raum in ein Netz von Zellen. Die Tabelle ist oft ein Array mit zwei oder mehr Indizes (genannt a Gitterdatei, Gitterindex, Bucket Gridund ähnliche Namen) und die Hash -Funktion gibt einen Index zurück Tupel. Dieses Prinzip wird in großem Umfang verwendet Computergrafik, Computergeometrie und viele andere Disziplinen, um viele zu lösen Proximity -Probleme in dem Flugzeug oder in dreidimensionaler Raum, wie das Finden engste Paare In einer Reihe von Punkten ähnliche Formen in einer Liste von Formen, ähnlich Bilder in einem (n Bilddatenbank, usw.
Hash -Tabellen werden auch zur Implementierung verwendet assoziative Arrays und Dynamische Sets.[4]
Eigenschaften
Gleichmäßigkeit
Eine gute Hash -Funktion sollte die erwarteten Eingaben so gleichmäßig wie möglich über den Ausgangsbereich abbilden. Das heißt, jeder Hash -Wert im Ausgangsbereich sollte mit ungefähr gleich generiert werden Wahrscheinlichkeit. Der Grund für diese letzte Anforderung ist, dass die Kosten für Hashing-basierte Methoden mit der Anzahl der Anzahl stark steigen Kollisionen- Die Eingänge, die dem gleichen Hash -Wert zugeordnet sind - entsteht. Wenn einige Hash -Werte eher auftreten als andere, muss ein größerer Teil der Suchvorgänge durch einen größeren Satz Colliding -Tabelleneinträge suchen.
Beachten Sie, dass dieses Kriterium nur den Wert erfordert gleichmäßig verteilt, nicht zufällig in jedem Sinne. Eine gute Randomisierungsfunktion ist (abgesehen von Berechnungseffizienzproblemen) im Allgemeinen eine gute Wahl als Hash -Funktion, aber das Gegenteil muss nicht wahr sein.
Hash -Tabellen enthalten oft nur eine kleine Teilmenge der gültigen Eingaben. Beispielsweise kann eine Club -Mitgliedschaftsliste nur hundert Mitgliedernamen aus der sehr großen Menge aller möglichen Namen enthalten. In diesen Fällen sollte das Gleichmäßigkeitskriterium fast alle typischen Teilmengen von Einträgen in der Tabelle enthalten, nicht nur für die globale Menge aller möglichen Einträge.
Mit anderen Worten, wenn ein typischer Satz von m Aufzeichnungen sind gehasht zu n Tischplätze, die Wahrscheinlichkeit, dass ein Eimer viel mehr als erhält m/n Aufzeichnungen sollten verschwindend klein sein. Insbesondere wenn, wenn m ist weniger als n, nur sehr wenige Eimer sollten mehr als ein oder zwei Datensätze haben. Eine kleine Anzahl von Kollisionen ist praktisch unvermeidlich, auch wenn n ist viel größer als m - Siehe Geburtstagsproblem.
In besonderen Fällen, in denen die Schlüssel im Voraus bekannt sind und der Schlüsselsatz statisch ist, kann eine Hash -Funktion festgestellt werden, die eine absolute (oder kollisionslose) Gleichmäßigkeit erreicht. Eine solche Hash -Funktion soll sein perfekt. Es gibt keine algorithmische Möglichkeit, eine solche Funktion zu konstruieren - nach einer zu suchen ist a Fakultät Funktion der Anzahl der Tasten, die zugeordnet werden sollen, im Vergleich zu der Anzahl der Tabellensteckplätze, in die sie angezogen werden. Eine perfekte Hash -Funktion über mehr als nur einen sehr kleinen Satz von Schlüssel zu finden, ist in der Regel rechnerisch nicht zu tun. Die resultierende Funktion ist wahrscheinlich rechnerisch komplexer als eine Standard -Hash -Funktion und bietet nur einen marginalen Vorteil gegenüber einer Funktion mit guten statistischen Eigenschaften, die eine minimale Anzahl von Kollisionen erzielen. Sehen Universelle Hash -Funktion.
Test und Messung
Beim Testen einer Hash -Funktion kann die Gleichmäßigkeit der Verteilung der Hash -Werte durch die bewertet werden Chi-Quadrat-Test. Dieser Test ist eine Anpassungsmaßnahme: Er ist die tatsächliche Verteilung von Elementen in Eimern gegenüber der erwarteten (oder gleichmäßigen) Verteilung von Elementen. Die Formel lautet:
wo: ist die Anzahl der Schlüssel, ist die Anzahl der Eimer, ist die Anzahl der Elemente im Eimer
Ein Verhältnis innerhalb eines Konfidenzintervalls (0,95 - 1,05) weist darauf hin, dass die bewertete Hash -Funktion eine erwartete einheitliche Verteilung aufweist.
Hash -Funktionen können einige technische Eigenschaften haben, die es wahrscheinlicher machen, dass sie bei der Anwendung eine einheitliche Verteilung haben. Einer ist das Strenge Avalanche -Kriterium: Wenn ein einzelnes Eingangsbit ergänzt wird, ändert sich jeder der Ausgangsbits mit einer Wahrscheinlichkeit von 50%. Der Grund für diese Eigenschaft ist, dass ausgewählte Teilmengen des Schlüsselspace möglicherweise eine geringe Variabilität aufweisen. Damit der Ausgang einheitlich verteilt werden soll, sollte eine geringe Variabilität, sogar ein Bit, zu einer hohen Variabilität (d. H. Verteilung über den Tablespace) im Ausgang führen. Jedes Bit sollte sich mit einer Wahrscheinlichkeit von 50% ändern, da sich die Schlüsseln um diese Werte um diese Werte befassen. Wenn sich die Bits zu leicht ändern möchten, nähert sich die Zuordnung einer festen XOR -Funktion eines einzelnen Bits. Standardtests für diese Eigenschaft wurden in der Literatur beschrieben.[5] Die Relevanz des Kriteriums für eine multiplikative Hash -Funktion wird hier bewertet.[6]
Effizienz
In Datenspeicher- und Abrufanwendungen ist die Verwendung einer Hash-Funktion ein Kompromiss zwischen Suchzeit und Datenspeicherraum. Wenn die Suchzeit unbegrenzt wäre, wäre eine sehr kompakte, nicht ordnungsgemäße lineare Liste das beste Medium. Wenn der Speicherplatz uneingeschränkt wäre, wäre eine zufällig zugängliche Struktur, die vom Schlüsselwert indexiert werden kann, sehr groß, sehr spärlich, aber sehr schnell. Eine Hash -Funktion benötigt eine begrenzte Zeit, um einen potenziell großen Schlüsselraum einer praktikablen Menge an Speicherplatz abzubilden, die unabhängig von der Anzahl der Schlüssel in einer begrenzten Zeit durchsucht werden können. In den meisten Anwendungen sollte die Hash -Funktion mit minimaler Latenz und sekundär in einer Mindestanzahl von Anweisungen berechnet werden.
Die Computerkomplexität variiert mit der Anzahl der erforderlichen Anweisungen und der Latenz einzelner Anweisungen, wobei die einfachsten die bitweisen Methoden (Falten) sind, gefolgt von den multiplikativen Methoden, und die komplexesten (langsamsten) sind die aufteilungsbasierten Methoden.
Da Kollisionen selten sein sollten und eine marginale Verzögerung verursachen, aber ansonsten harmlos sind, ist es normalerweise vorzuziehen, eine schnellere Hash -Funktion über eine zu wählen, die mehr Berechnung benötigt, aber einige Kollisionen spart.
Aufteilungsbasierte Implementierungen können von besonderer Bedeutung sein, da die Abteilung bei nahezu allen Chip-Architekturen mikroprogrammiert ist. Teilen (Modulo) durch eine Konstante kann invertiert werden, um durch das multiplikative Inverse der Konstanten mit wortgröße zu multiplizieren. Dies kann vom Programmierer oder vom Compiler erfolgen. Die Divide kann auch direkt in eine Reihe von Schicht-Subtrahieren und Schichtadds reduziert werden, obwohl die Minimierung der erforderlichen Anzahl solcher Vorgänge ein entmutigendes Problem ist. Die Anzahl der daraus resultierenden Montageanweisungen kann mehr als ein Dutzend betragen und die Pipeline überfluten. Wenn die Architektur Hardware-Multiply-Funktionseinheiten aufweist, ist der Multiply-by-Inverse wahrscheinlich ein besserer Ansatz.
Wir können die Tischgröße zulassen n nicht eine Kraft von sein 2 und müssen immer noch keinen Rest- oder Abteilungsbetrieb ausführen, da diese Berechnungen manchmal kostspielig sind. Zum Beispiel lassen n signifikant weniger sein als 2b. Betrachten Sie a Pseudorandom -Zahlengenerator Funktion P(Schlüssel) Das ist einheitlich in der Intervall [0, 2b- 1]. Eine Hash -Funktionsuniform im Intervall [0,, n-1] ist n P(Schlüssel)/2b. Wir können die Abteilung durch ein (möglicherweise schneller) rechts ersetzen Bitverschiebung: np(Schlüssel) >> b.
Wenn die Schlüssel wiederholt gehasht werden und die Hash -Funktion kostspielig ist, kann die Rechenzeit gespeichert werden, indem die Hash -Codes vorab vorangekommen und mit den Schlüsseln gespeichert werden. Übereinstimmende Hash -Codes bedeutet mit ziemlicher Sicherheit, dass die Schlüssel identisch sind. Diese Technik wird für die Transpositionstabelle in Game-Playing-Programmen verwendet, in der eine 64-Bit-Hashed-Darstellung der Boardposition gespeichert ist.
Universalität
A Universal Hashing Schema ist a Randomisierter Algorithmus Das wählt eine Hashing -Funktion aus h Unter einer Familie solcher Funktionen so, dass die Wahrscheinlichkeit einer Kollision zweier verschiedener Schlüssel ist 1/m, wo m ist die Anzahl der gewünschten Hash -Werte - unabhängig von den beiden Schlüssel. Universal Hashing sorgt für eine Verteilung der Eingabedaten (in einem probabilistischen Sinne), dass sich die Hash -Funktionsanwendung sowohl verhalten wird als eine zufällige Funktion. Es wird jedoch mehr Kollisionen als perfektes Hashing haben und benötigen möglicherweise mehr Operationen als eine Spezial-Hash-Funktion.
Anwendbarkeit
Eine Hash -Funktion gilt in verschiedenen Situationen. Eine Hash -Funktion, die nur bestimmte Tabellengrößen, Zeichenfolgen nur bis zu einer bestimmten Länge ermöglicht oder keinen Samen akzeptieren kann (d. H. Double Hashing zulassen), ist nicht so nützlich wie eine, die dies tut.
Deterministisch
Ein Hash -Verfahren muss sein deterministisch—Meneinigung dafür, dass es für einen bestimmten Eingangswert immer den gleichen Hash -Wert erzeugen muss. Mit anderen Worten, es muss a sein Funktion der Daten im mathematischen Sinne des Begriffs gehasht werden. Diese Anforderung schließt Hash -Funktionen aus, die von externen variablen Parametern abhängen, wie z. Pseudo-Random-Zahlengeneratoren oder die Tageszeit. Es schließt Funktionen auch aus Müllsammlung), obwohl manchmal das Räumen des Gegenstandes möglich ist.
Der Determinismus steht im Kontext der Wiederverwendung der Funktion. Zum Beispiel, Python Fügt die Funktion hinzu, dass Hash -Funktionen einen randomisierten Saatgut verwenden, der einmal generiert wird, wenn der Python -Prozess zusätzlich zu dem zu hashierten Eingang beginnt.[7] Der Python -Hash (Siphash) ist immer noch eine gültige Hash -Funktion, wenn sie innerhalb eines einzelnen Laufs verwendet wird. Wenn die Werte jedoch bestehen bleiben (z. B. an die Festplatte geschrieben), können sie nicht mehr als gültige Hash -Werte behandelt werden, da sich der Zufallswert im nächsten Lauf unterscheiden kann.
Definierter Bereich
Es ist oft wünschenswert, dass die Ausgabe einer Hash -Funktion eine feste Größe hat (siehe unten). Wenn beispielsweise der Ausgang auf 32-Bit-Ganzzahlwerte beschränkt ist, können die Hash-Werte verwendet werden, um in ein Array zu indexieren. Ein solches Hashing wird üblicherweise zur Beschleunigung der Datensuche verwendet.[8] Die Erzeugung der Ausgabe mit fester Länge aus der Eingabe der variablen Länge kann erreicht werden, indem die Eingangsdaten in Stücke mit spezifischer Größe zerlegt werden. Hash -Funktionen, die für Datensuche verwendet werden, verwenden einen arithmetischen Ausdruck, der iterativ die Teile der Eingabe (wie die Zeichen in einer Zeichenfolge) verarbeitet, um den Hash -Wert zu erzeugen.[8]
Variabler Bereich
In vielen Anwendungen kann der Bereich der Hash -Werte für jeden Programmlauf unterschiedlich sein oder sich entlang desselben Laufs ändern (z. B. wenn eine Hash -Tabelle erweitert werden muss). In diesen Situationen benötigt man eine Hash -Funktion, die zwei Parameter nimmt - die Eingabedaten zund die Nummer n von erlaubten Hash -Werten.
Eine häufige Lösung besteht darin, eine feste Hash -Funktion mit einem sehr großen Bereich zu berechnen (z. B., 0 zu 232- 1), trennen Sie das Ergebnis durch n, und benutze die Abteilung Rest. Wenn n ist selbst eine Kraft von 2Dies kann durch erledigt werden durch Bitmaskierung und Bit wechseln. Wenn dieser Ansatz verwendet wird, muss die Hash -Funktion ausgewählt werden 0 und n- 1für jeden Wert von n Dies kann in der Anwendung auftreten. Abhängig von der Funktion kann der Rest nur für bestimmte Werte von einheitlich sein n, z.B. seltsam oder Primzahlen.
Variabler Bereich mit minimaler Bewegung (dynamische Hash -Funktion)
Wenn die Hash -Funktion verwendet wird, um Werte in einer Hash -Tabelle zu speichern, die den Lauf des Programms überlebt, und die Hash -Tabelle erweitert oder geschrumpft werden muss, wird die Hash -Tabelle als dynamische Hash -Tabelle bezeichnet.
Eine Hash -Funktion, die die minimale Anzahl von Datensätzen bei der Änderung der Tabelle verlagert, ist wünschenswert. Was benötigt wird, ist eine Hash -Funktion H(z,n)- wo z ist der Schlüssel, der gehasht wird und n ist die Anzahl der erlaubten Hash -Werte - so dass H(z,n+1) = H(z,n) mit der Wahrscheinlichkeit nahe bei n/(n+1).
Lineares Hashing und Spiralspeicher sind Beispiele für dynamische Hash -Funktionen, die in ständiger Zeit ausgeführt werden, aber die Eigenschaft der Gleichmäßigkeit entspannen, um die minimale Bewegungseigenschaft zu erreichen. Verlängerbares Hashing Verwendet eine dynamische Hash -Funktion, die Platz proportional zu erfordert n Um die Hash -Funktion zu berechnen, wird sie zu einer Funktion der vorherigen Tasten, die eingefügt wurden. Mehrere Algorithmen, die die Gleichmäßigkeitseigenschaft bewahren, aber Zeit proportional zu erfordern n den Wert von berechnen H(z,n) wurden erfunden.[Klarstellung erforderlich]
Eine Hash -Funktion mit minimaler Bewegung ist besonders nützlich in Verteilte Hash -Tabellen.
Datennormalisierung
In einigen Anwendungen können die Eingabedaten Funktionen enthalten, die für Vergleichszwecke irrelevant sind. Wenn Sie beispielsweise einen persönlichen Namen nachschlagen, kann es wünschenswert sein, die Unterscheidung zwischen oberen und unteren Fallbuchstaben zu ignorieren. Für solche Daten muss man eine Hash -Funktion verwenden, die mit den Daten kompatibel ist Gleichwertigkeit Die Verwendung von Kriterien: Das heißt, zwei beliebige Eingaben, die als gleichwertig betrachtet werden, müssen den gleichen Hash -Wert ergeben. Dies kann erreicht werden, indem die Eingabe vor dem Hash-Hemdung normalisiert wird.
Hashing Ganzzahl Datentypen
Es gibt mehrere gemeinsame Algorithmen für Hashing -Ganzzahlen. Die Methode, die die beste Verteilung gibt, ist datenabhängig. Eine der einfachsten und häufigsten Methoden in der Praxis ist die Methode der Modulo -Division.
Identitäts -Hash -Funktion
Wenn die zu Hasheds zu Hashed sind klein genug sind, kann man die Daten selbst (neu interpretiert als Ganzzahl) als Hash -Wert verwenden. Die Kosten für die Berechnung dessen Identität Die Hash -Funktion ist effektiv Null. Diese Hash -Funktion ist perfekt, wie es jeden Eingang auf einen unterschiedlichen Hash -Wert ordnet.
Die Bedeutung von "klein genug" hängt von der Größe des Typs ab, der als Hash -Wert verwendet wird. Zum Beispiel in JavaDer Hash-Code ist eine 32-Bit-Ganzzahl. Somit die 32-Bit-Ganzzahl Ganze Zahl
und 32-Bit-Schwimmpunkt Schweben
Objekte können den Wert einfach direkt verwenden. während die 64-Bit-Ganzzahl Lang
und 64-Bit-Schwimmpunkt Doppelt
kann diese Methode nicht verwenden.
Andere Datenarten können dieses Hashing -Schema auch verwenden. Zum Beispiel beim Zuordnen Charakterzeichenfolgen zwischen Groß-und KleinschreibungMan kann die binäre Codierung jedes Zeichens verwenden, das als Ganzzahl interpretiert wird, um eine Tabelle zu indizieren, die die alternative Form dieses Zeichens angibt ("A" für "a", "8" für "8" usw.). Wenn jeder Charakter in 8 Bit gespeichert ist (wie in erweitertem Charakter ASCII[9] oder ISO Latein 1), die Tabelle hat nur 28 = 256 Einträge; Im Falle des Unicode Zeichen, die Tabelle hätte 17 × 216 = 1114112 Einträge.
Die gleiche Technik kann verwendet werden, um die Kartierung zu erstellen Zwei-Buchstaben-Landcodes wie "uns" oder "Za" zu Landnamen (262 = 676 Tabelleneinträge), 5-stellige Postleitzahlen wie 13083 für Stadtnamen (Namen (namens Stadtnamen) (100000 Einträge) usw. Ungültige Datenwerte (z. B. der Ländercode "xx" oder die Postleitzahl 00000) können in der Tabelle undefiniert bleiben oder auf einen geeigneten "Null" -Wert zugeordnet werden.
Triviale Hash -Funktion
Wenn die Schlüssel gleichmäßig oder einheitlich über den Schlüsselraum verteilt sind, so dass die Schlüsselwerte im Wesentlichen zufällig sind, können sie als „Hashed“ angesehen werden. In diesem Fall kann eine beliebige Anzahl von Bits im Schlüssel gewählt werden[Klarstellung erforderlich] aus und als Index in die Hash -Tabelle zusammengefasst. Zum Beispiel könnte eine einfache Hash -Funktion die am wenigsten signifikant maskieren m Bits und verwenden Sie das Ergebnis als Index in eine Hash -Tabelle mit Größe 2m.
Falten
Ein Falthash -Code wird erzeugt, indem die Eingabe in n -Abschnitte von M -Bits geteilt wird, wobei 2m ist die Tabellengröße und unter Verwendung eines bitgewiären Vorgangs der Paritätsvorsorge wie Add oder XOR, um die Abschnitte zu kombinieren, gefolgt von einer Maske oder einer Verschiebung, um überschüssige Bits am hohen oder niedrigen Ende abzuschneiden. Beispielsweise gibt es für eine Tabellengröße von 15 Bit und den Schlüsselwert von 0x0123456789ABCDEF fünf Abschnitte aus 0x4def, 0x1357, 0x159e, 0x091a und 0x8. Hinzu kommen wir 0x7aa4, einen 15-Bit-Wert.
Mittelquadrat
Ein Mid-Squares-Hash-Code wird erzeugt, indem die Eingabe quadriert und eine geeignete Anzahl mittlerer Ziffern oder Bits extrahiert wird. Wenn der Eingang beispielsweise 123.456.789 und die Hash-Tabellengröße 10.000 beträgt, produziert der Schlüssel 15.241.578.750.190.521, so Die Methode erzeugt einen vernünftigen Hash -Code, wenn nicht viele führende oder nachfolgende Nullen im Schlüssel sind. Dies ist eine Variante des multiplikativen Hashings, aber nicht so gut, da ein willkürlicher Schlüssel kein guter Multiplikator ist.
Division Hashing
Eine Standardtechnik besteht darin, eine Modulo -Funktion auf dem Schlüssel zu verwenden, indem ein Divisor ausgewählt wird Das ist eine Primzahl in der Nähe der Tabellengröße, also . Die Tabellengröße ist normalerweise eine Leistung von 2. Dies ergibt eine Verteilung von . Dies liefert gute Ergebnisse bei einer großen Anzahl von Schlüsselsätzen. Ein bedeutender Nachteil von Division Hashing ist, dass die Teilung bei den meisten modernen Architekturen, einschließlich X86, mikroprogrammiert ist und 10 -mal langsamer sein kann als multiplizieren. Ein zweiter Nachteil ist, dass es keine Cluster -Schlüssel aufbaut. Zum Beispiel die Schlüssel 123000, 456000, 789000 usw. modulo 1000 alle zu derselben Adresse. Diese Technik funktioniert in der Praxis gut, da viele Schlüsselsätze bereits ausreichend zufällig sind und die Wahrscheinlichkeit, dass ein Schlüsselsatz von einer großen Primzahl zyklisch ist, gering ist.
Algebraische Kodierung
Die algebraische Codierung ist eine Variante der Hashing -Methode der Division, die Teilung durch ein Polynommodulo 2 anstelle einer Ganzzahl verwendet, um N -Bits auf M -Bits zuzuordnen.[10] Bei diesem Ansatz, und wir postulieren eine TH Grad Polynom . Ein Schlüssel kann als Polynom angesehen werden . Der Rest unter Verwendung von Polynomarithmetikmodulo 2 ist . Dann . Wenn Es ist konstruiert, dass sie nicht oder weniger nicht-Null-Koeffizienten haben, dann kollidiert Schlüssel, die weniger als T-Bits teilen.
Z Eine Funktion von k, t und n, einem Teil des 2k-1, ist aus der GF (2) gebautk) aufstellen. Knuth gibt ein Beispiel: für n = 15, m = 10 und t = 7, . Die Ableitung lautet wie folgt:
Lassen Seien Sie der kleinste Satz von ganzen Zahlen, so dass und .[Anmerkungen 2]
Definieren wo und wo die Koeffizienten von werden in diesem Bereich berechnet. Dann der Grad von . Seit ist eine Wurzel von Wann immer ist eine Wurzel, folgt, dass die Koeffizienten von erfüllen Sie sind also alle 0 oder 1. wenn ist ein Polynommodulo 2 ungleich Null mit höchstens t ungleich Null -Koeffizienten ist kein Vielfaches von Modulo 2.[Anmerkungen 3] Wenn folgt, dass die entsprechende Hash -Funktion Tasten mit weniger als T -Bits gemeinsam für einzigartige Indizes kartiert.[11]
Das übliche Ergebnis ist, dass entweder N groß wird oder Twill groß oder beides wird, damit das Schema rechnerisch machbar ist. Daher ist es eher für die Hardware- oder Mikrocode -Implementierung geeignet.[12]
Einzigartiges Permutation Hashing
Siehe auch einzigartiges Permutationshashing, das eine garantierte Bestandszeit für schlechteste Fälle hat.[13]
Multiplikatives Hashing
Standard multiplikatives Hashing verwendet die Formel das erzeugt einen Hash -Wert in . Der Wert ist ein entsprechend ausgewählter Wert, der sein sollte relativ primär zu ; Es sollte groß sein[Klarstellung erforderlich] und seine binäre Darstellung eine zufällige Mischung[Klarstellung erforderlich] von 1 und 0. Ein wichtiger praktischer Sonderfall tritt auf, wenn und sind Kräfte von 2 und ist die Maschine Wortgröße. In diesem Fall wird diese Formel . Dies ist etwas Besonderes, weil das arithmetische Modulo wird standardmäßig in Programmiersprachen auf niedriger Ebene durchgeführt und die ganze Zahl von 2 ist einfach ein Rechtsverschiebung. In C wird diese Funktion beispielsweise in C
vorzeichenloser Hash (nicht signiert k) {return (a*k) >> (W-m); }
und für fest und Dies führt zu einer einzelnen Ganzzahl-Multiplikation und Rechten, wodurch sie zu einer der schnellsten Hash-Funktionen berechnet wird.
Multiplikatives Hashing ist anfällig für einen "häufigen Fehler", der zu einer schlechten Diffusion führt-hochwertige Werteingangsbits beeinflussen keine Ausgangsbits mit niedrigerem Wert.[14] Eine Transmutation für den Eingang, der die Spannweite der zurückgehaltenen Top -Top -Stücke und XORS verlagert oder zum Schlüssel hinzufügt, bevor der Multiplikationsschritt dafür korrigiert wird. Die resultierende Funktion sieht also aus:[15]
vorzeichenloser Hash (nicht signiert k) {k ^= k >> (w-m); return (a*k) >> (w-m); }
Fibonacci Hashing
Fibonacci Hashing ist eine Form von multiplikativem Hashing, bei dem der Multiplikator ist , wo Ist die maschinelle Wortlänge und (Phi) ist das Goldener Schnitt (ungefähr 5/3). Eine Eigenschaft dieses Multiplikators ist, dass er einheitlich über den Tischraum verteilt wird. Blöcke von aufeinanderfolgenden Schlüssel in Bezug auf jeden Block von Bits im Schlüssel. Konsekutive Schlüssel innerhalb der hohen Bits oder niedrigen Tasten des Schlüssels (oder eines anderen Feldes) sind relativ häufig. Die Multiplikatoren für verschiedene Wortlängen sind:
- 16: a = 4050310
- 32: a = 265443576910
- 48: a = 17396110258977110[Notizen 4]
- 64: a = 1140071481932319848510[Anmerkungen 5]
Zobrist Hashing
Tabelle Hashing, allgemeiner bekannt als Zobrist Hashing nach Albert Zobrist, ein amerikanischer Informatiker, ist eine Methode, um universelle Familien von Hash -Funktionen zu konstruieren, indem Tabellen -Lookup mit XOR -Operationen kombiniert werden. Dieser Algorithmus hat sich für Hashing-Zwecke als sehr schnell und von hoher Qualität erwiesen (insbesondere Hashing von Ganzzahl-Number-Schlüssel).[16]
Zobrist Hashing wurde ursprünglich eingeführt, um die Schachpositionen in Computerspielprogrammen kompakt zu repräsentieren. Eine eindeutige Zufallszahl wurde zugewiesen, um jede Art von Stück (jeweils sechs für Schwarz und Weiß) auf jedem Raum der Platine darzustellen. Somit wird eine Tabelle von 64x12 solcher Zahlen zu Beginn des Programms initialisiert. Die Zufallszahlen könnten länger sein, aber 64 Bit waren aufgrund der 64 Quadrate auf der Tafel natürlich. Eine Position wurde transkribiert, indem das Radfahren durch die Teile in einer Position durchfahren, die entsprechenden Zufallszahlen indiziert wurde (freie Räume wurden nicht in die Berechnung einbezogen) und Xoring zusammen (der Startwert könnte 0 sein, der Identitätswert für XOR oder ein Zufall Samen). Der resultierende Wert wurde durch Modulo, Falten oder einen anderen Betrieb reduziert, um einen Hash -Tabellenindex zu erstellen. Der ursprüngliche Zobrist -Hash wurde in der Tabelle als Darstellung der Position gespeichert.
Später wurde die Methode auf Hashing-Ganzzahlen ausgedehnt, indem jedes Byte in jeder von 4 möglichen Positionen im Wort durch eine eindeutige 32-Bit-Zufallszahl dargestellt wurde. Somit eine Tabelle von 28x4 solcher Zufallszahlen werden konstruiert. Eine 32-Bit-Hashed-Ganzzahl wird transkribiert, indem die Tabelle mit dem Wert jedes Byte des einfachen Textgeistes und Xoring der geladenen Werte zusammen indexiert ist (wiederum kann der Startwert der Identitätswert oder ein zufälliger Saatgut sein). Die natürliche Erweiterung auf 64-Bit-Ganzzahlen erfolgt mit einer Tabelle von 28X8 64-Bit-Zufallszahlen.
Diese Art von Funktion hat einige schöne theoretische Eigenschaften, von denen eine genannt wird 3-Tupel-Unabhängigkeit Dies bedeutet, dass jeder 3-Tupel von Schlüssel gleichermaßen auf 3-Tupel von Hash-Werten abgebildet wird.
Customized Hash -Funktion
Eine Hash -Funktion kann so konzipiert werden, dass sie vorhandene Entropie in den Tasten ausnutzt. Wenn die Schlüssel führende oder nachfolgende Nullen oder bestimmte Felder haben, die nicht genutzt, immer Null oder eine andere Konstante sind oder im Allgemeinen nur wenig variieren, wird nur die flüchtigen Teile maskieren und Hashing auf diesen bietet eine bessere und möglicherweise schnellere Hash -Funktion. Ausgewählte Divisoren oder Multiplikatoren in der Abteilung und in multiplikativen Systemen können einheitlichere Hash -Funktionen erfüllen, wenn die Schlüssel zyklisch sind oder andere Entlassungen haben.
Hashing-Daten mit variabler Länge
Wenn die Datenwerte lang sind (oder variable Länge) Charakterzeichenfolgen- wie persönliche Namen, Webseitenadressen, oder Mail -Nachrichten - Ihre Verteilung ist normalerweise sehr uneben, mit komplizierten Abhängigkeiten. Zum Beispiel Text in jedem Natürliche Sprache hat hoch ungleichmäßige Verteilungen von Figuren, und Charakterpaare, charakteristisch für die Sprache. Für solche Daten ist es ratsam, eine Hash -Funktion zu verwenden, die von allen Zeichen der Zeichenfolge abhängt - und auf andere Weise von jedem Zeichen abhängt.[Klarstellung erforderlich]
Mitte und endet
Simpilistische Hash -Funktionen können die erste und die letzte hinzufügen n Zeichen einer Zeichenfolge zusammen mit der Länge oder bilden einen Hash-Größe-Hash aus den mittleren 4 Zeichen einer Zeichenfolge. Dies speichert die Iterie über die (potenziell lange) Zeichenfolge, aber Hash -Funktionen, die nicht auf allen Zeichen einer Zeichenfolge durch Hash -Hash aufgrund von Redundanzen, Clustering oder anderen Pathologien im Schlüsselsatz linear werden können. Solche Strategien können als benutzerdefinierte Hash -Funktion wirksam sein, wenn die Struktur der Schlüssel so ist, dass entweder die Mitte, die Enden oder andere Felder Null oder eine andere invariante Konstante sind, die die Schlüssel nicht unterscheidet. Dann können die invarianten Teile der Schlüssel ignoriert werden.
Zeichenfaltung
Das paradigmatische Beispiel für die Faltung durch Zeichen besteht darin, die Ganzzahlwerte aller Zeichen in der Zeichenfolge hinzuzufügen. Eine bessere Idee ist es, den Hash -Gesamtbetrag mit einer konstanten, typischerweise eine beträchtliche Primzahl zu multiplizieren, bevor das nächste Charakter hinzufügt und Überlauf ignoriert. Die Verwendung von exklusivem 'oder' anstelle von Add ist auch eine plausible Alternative. Der endgültige Vorgang wäre ein Modulo, eine Maske oder eine andere Funktion, um den Wortwert auf einen Index der Größe der Tabelle zu reduzieren. Die Schwäche dieses Verfahrens besteht darin, dass Informationen sich in den oberen oder unteren Bits der Bytes gruppieren können, die das Clustering im Hashed -Ergebnis verbleiben und mehr Kollisionen verursachen als ein ordnungsgemäßer randomisierender Hash. ASCII-BYTE-Codes haben beispielsweise ein oberes Bit von 0 und druckbare Zeichenfolgen verwenden nicht die ersten 32 Byte-Codes, daher werden die Informationen (95-Byte-Codes) auf unvorhergesehene Weise in den verbleibenden Bits zusammengefasst.
Der klassische Ansatz nannte die PJW Hash Basierend auf der Arbeit von Peter. J. Weinberger bei Att Bell Labs in den 1970er Jahren wurde ursprünglich für Hashing -Identifikatoren in Compiler -Symboltabellen entwickelt, wie in der "Dragon Book".[17] Diese Hash -Funktion setzt die Bytes 4 Bit aus, bevor sie zusammengefügt werden. Wenn sich die Menge abwickelt, werden die hohen 4-Bits ausgeschaltet und falls ungleich Null in das niedrige Byte der kumulativen Menge zurückgeführt. Das Ergebnis ist ein Word -Hash -Code, auf den ein Modulo oder ein anderer Reduzierungsvorgang angewendet werden kann, um den endgültigen Hash -Index zu erstellen.
Heute, insbesondere mit dem Aufkommen von 64-Bit-Wortgrößen, ist viel effizienteres String-Hashing durch Wortbrocken mit variabler Länge verfügbar.
Wortlänge Faltung
Moderne Mikroprozessoren ermöglichen eine viel schnellere Verarbeitung, wenn 8-Bit-Zeichenketten nicht durch die Verarbeitung eines Charakters nach dem anderen gehasht werden, sondern die Zeichenfolge als Array von 32 Bit- oder 64-Bit-Ganzzahlen interpretiert und dieses "breite Wort" Hashing/Acumulation " Ganzzahlwerte mittels arithmetischer Operationen (z. B. Multiplikation durch Konstante und Bitverschiebung). Das endgültige Wort, das möglicherweise nicht besetzte Bytepositionen hat, ist mit Nullen oder einem angegebenen "randomisierenden" Wert gefüllt, bevor er in den Hash gefaltet wird. Der akkumulierte Hash -Code wird durch ein endgültiges Modulo oder einen anderen Betrieb reduziert, um einen Index in die Tabelle zu erhalten.
Radix Conversion Hashing
Analog zu der Art und Weise, wie eine ASCII- oder Ebcdic -Zeichenfolge, die eine Dezimalzahl darstellt (x0ak–1+x1ak–2+...+xk–2a+xk–1). Dies ist einfach ein Polynom in einem Radix ungleich Null a! = 1 Das erfordert die Komponenten (x0,x1, ...,xk–1) als Zeichen der Eingabezeichenfolge der Länge k. Es kann direkt als Hash -Code oder als Hash -Funktion verwendet werden, um den potenziell großen Wert der Hash -Tabellengröße abzubilden. Der Wert von a ist normalerweise eine Primzahl, die mindestens groß genug ist, um die Anzahl der verschiedenen Zeichen im Zeichen der potenziellen Schlüssel zu halten. Radix Conversion Hashing von Saiten minimiert die Anzahl der Kollisionen.[18] Die verfügbaren Datengrößen können die maximale Länge der Zeichenfolge einschränken, die mit dieser Methode gehasht werden kann. Beispielsweise wird ein 128-Bit-doppeltes Long-Wort nur eine alphabetische Saite von 26 Zeichen (ignorieren Sie Fall) mit einem Radix von 29; Eine druckbare ASCII-Zeichenfolge ist mit Radix 97 und einem 64-Bit-langen Wort auf 9 Zeichen begrenzt. Alphabetische Schlüssel sind jedoch normalerweise von bescheidener Länge, da Schlüssel in der Hash -Tabelle gespeichert werden müssen. Numerische Zeichenketten sind normalerweise kein Problem; 64 Bit können bis zu 1019, oder 19 Dezimalstellen mit Radix 10.
Rolling Hash
In einigen Anwendungen, wie z. Substring -Suche, man kann eine Hash -Funktion berechnen h für jeden k-Charakter Substring von einem gegebenen n-Character -Zeichenfolge durch Vorrücken eines Breitenfensters k Zeichen entlang der Zeichenfolge; wo k ist eine feste Ganzzahl, und n ist größer als k. Die einfache Lösung, die darin besteht, ein solches Substring an jeder Zeichenposition im Text zu extrahieren und zu berechnen h separat erfordert eine Reihe von Operationen, die proportional zu k·n. Jedoch mit der richtigen Wahl von hMan kann die Technik des Rolling -Hashs verwenden, um all diese Hashes mit einem Aufwand proportional zu berechnen zu berechnen mk+n wo m ist die Anzahl der Vorkommen des Substring.[19][Was ist die Wahl von H?]
Der bekannteste Algorithmus dieses Typs ist Rabin-Karp mit bestem und durchschnittlicher Fallleistung O(n+mk) und schlimmster Fall O(n·k) (Fairness ist der schlimmste Fall hier schwer pathologisch: Sowohl die Textzeichenfolge als auch die Substring bestehen aus einem wiederholten Einzelcharakter, wie z. t= "Aaaaaaaaaaaa" und s= "Aaa"). Die für den Algorithmus verwendete Hash -Funktion ist normalerweise die Rabin -Fingerabdruck, entwickelt, um Kollisionen in 8-Bit-Charakter-Saiten zu vermeiden, aber auch andere geeignete Hash-Funktionen werden verwendet.
Analyse
Das schlimmste Fall -Ergebnis für eine Hash -Funktion kann zwei Arten bewertet werden: theoretisch und praktisch. Der theoretische schlimmste Fall ist die Wahrscheinlichkeit, dass alle Schlüssel zu einem einzelnen Steckplatz zugeordnet sind. Praktischer schlimmster Fall wird erwartet, dass die längste Sondensequenz (Hash -Funktion + Kollisionsauflösungsmethode). Diese Analyse berücksichtigt einheitliches Hashing, dh jeder Schlüssel wird einem bestimmten Steckplatz mit Wahrscheinlichkeit zugeordnet 1/m, charakteristisch für universelle Hash -Funktionen.
Während sich Knuth über den kontroversen Angriff auf Echtzeitsysteme befürchtet,[20] Gonnet hat gezeigt, dass die Wahrscheinlichkeit eines solchen Falls "lächerlich klein" ist. Seine Darstellung war, dass die Wahrscheinlichkeit von k von n Die Keys -Mapping zu einem einzigen Steckplatz ist wo α ist der Lastfaktor, n/m.[21]
Geschichte
Der Begriff Hash Bietet eine natürliche Analogie mit seiner nicht-technischen Bedeutung (um etwas zu zerhacken oder durcheinander zu bringen), da HASH ihre Eingabedaten fungiert, um ihre Ausgabe abzuleiten.[22] In seiner Forschung für den genauen Ursprung des Begriffs, Donald Knuth bemerkt das während Hans Peter Luhn von IBM Es scheint der erste gewesen zu sein, der das Konzept einer Hash -Funktion in einem Memo vom Januar 1953 verwendete. Der Begriff selbst würde erst Ende der 1960er Jahre in Herbert Hellerman's in der veröffentlichten Literatur erscheinen Prinzipien des digitalen ComputersystemsObwohl es bis dahin bereits weit verbreitet war.[23]
Siehe auch
Anmerkungen
- ^ Dies ist nützlich in Fällen, in denen Schlüssel von einem böswilligen Agenten entwickelt werden, beispielsweise um einen DOS -Angriff zu verfolgen.
- ^ Zum Beispiel für n = 15, k = 4, t = 6, [Knuth]
- ^ Knuth überlässt dem Leser bequem den Beweis dafür.
- ^ Unisys große Systeme
- ^ 11400714819323198486 ist näher, aber das untere Bit ist Null und wirft im Wesentlichen etwas weg. Die nächstgelegene ungerade Zahl ist die angegebene.
Verweise
- ^ Schueffel, Patrick; Groeneweg, Nikolaj; Baldegger, Rico (2019). Die Krypto -Enzyklopdie - Münzen, Token und digitale Vermögenswerte von a bis z. Bern, Friborg: Wachstumsverlag / Heg Friborg. p. 27. ISBN 978-2-940384-47-1.
- ^ Knuth, D. 1973, The Art of Computer Programing, Vol. 3, sortieren und suchen, S. 527. Addison-Wesley, Reading, MA., USA
- ^ Stokes, Jon (2002-07-08). "CPU -Caching und Leistung verstehen". ARS Technica. Abgerufen 2022-02-06.
- ^ Menezes, Alfred J.; Van Oorschot, Paul C.; Vanstone, Scott A (1996). Handbuch der angewandten Kryptographie. CRC Press. ISBN 978-0849385230.
- ^ Castro et al., 2005, "The Strict Avalanche Criterion Randomness Test", Mathematik und Computer in Simulation 68 (2005) 1–7, Elsevier,
- ^ Malte Sharupke, 2018, "Fibonacci Hashing: Die Optimierung, die die Welt vergessen hat (OR: eine bessere Alternative zum Ganzzahlmodulo)"
- ^ "3. Datenmodell - Python 3.6.1 Dokumentation". docs.python.org. Abgerufen 2017-03-24.
- ^ a b Sedgebick, Robert (2002). "14. Hashing". Algorithmen in Java (3 ed.). Addison Wesley. ISBN 978-0201361209.
- ^ Plain ASCII ist eine 7-Bit-Charakter-Codierung, obwohl es oft in 8-Bit-Bytes mit dem Bit höchsten Ordnung (Null) gespeichert wird. Daher haben die Bytes für einfache ASCII nur 27 = 128 Gültige Werte, und die Zeichenübersetzungstabelle hat nur so viele Einträge.
- ^ Knuth, D. 1973, The Art of Computer Science, Vol. 3, sortieren und suche, S. 512-13. Addison-Wesley, Reading, MA., USA
- ^ Knuth, S. 542-43
- ^ Knuth, ebenda.
- ^ Dolev, Shlomi; Lahiani, Limor; Haviv, Yinnon (2013). "Einzigartige Permutation Hashing". Theoretische Informatik. 475: 59–65. doi:10.1016/j.tcs.2012.12.047.
- ^ "CS 3110 Vortrag 21: Hash -Funktionen".Sektion "multiplikatives Hashing".
- ^ Sharupke, Malte (16. Juni 2018). "Fibonacci Hashing: Die Optimierung, die die Welt vergessen hat". wahrscheinlichdance.com. WordPress.com.
- ^ Zobrist, Albert L. (April 1970), Eine neue Hashing -Methode mit Anwendung für Spielspiel (PDF), Technik. Rep. 88, Madison, Wisconsin: Abteilung für Computerwissenschaften, Universität von Wisconsin.
- ^ Aho, Sethi, Ullman, 1986, Compiler: Prinzipien, Techniken und Werkzeuge, S. 435. Addison-Wesley, Reading, MA.
- ^ Ramakrishna, M. V.; Zobel, Justin (1997). "Leistung in der Praxis von String -Hashing -Funktionen". Datenbanksysteme für erweiterte Anwendungen '97. Dasfaa 1997. S. 215–224. Citeseerx 10.1.1.18.7520. doi:10.1142/9789812819536_0023. ISBN 981-02-3107-5. S2CID 8250194. Abgerufen 2021-12-06.
- ^ "Finden Sie das längste Substring mit k -einzigartigen Zeichen in einer bestimmten Zeichenfolge". Geeksforgeeks. 2015-03-18. Abgerufen 2020-05-30.
- ^ Knuth, D. 1975, Art of Computer Programing, Vol. 3. Sortieren und Suchen, S. 540. Addison-Wesley, Reading, MA
- ^ Gonnet, G. 1978, "Erwartete Länge der längsten Sondensequenz bei Hash-Code-Suche", CS-RR-78-46, Universität Waterloo, Ontario, Kanada
- ^ Knuth, Donald E. (2000). Sortieren und Suchen (2. ed., 6. Druck, neu aktualisiert und rev. Ed.). Boston [U.A.]: Addison-Wesley. p. 514. ISBN 978-0-201-89685-5.
- ^ Knuth, Donald E. (2000). Sortieren und Suchen (2. ed., 6. Druck, neu aktualisiert und rev. Ed.). Boston [U.A.]: Addison-Wesley. S. 547–548. ISBN 978-0-201-89685-5.
Externe Links
- Berechnen Sie den Hash eines bestimmten Wertes von Timo Denk
- Die Goulburn Hashing -Funktion (PDF) von Mayur Patel
- Hash -Funktionskonstruktion für textuelle und geometrische Datenabnahme (PDF) Neueste Trends bei Computern, Band 2, S. 483–489, CSCC -Konferenz, Corfu, 2010