Programmieren 1 Prof. Dr.-Ing. Silvia Keller Studiengang Angewandte Informatik Ausgabe: 19.03.2004 Seite 104 von 110 7 Sortieren und Suchen nach dem Hash-Verfahren D AS PR OBLEM Gegeben ist eine Liste von Namen. Diese Namen sind mit einem Verfahren so zu sortieren, dass ein Name k mit dem gleichen Verfahren gesucht werden kann D IE 7.1 ID EE : SORTIEREN MIT HASH-FUNKTIONEN Man speichert die Namen in einer Liste mit M Elementen, also ein array, in dem M Werte Platz finden. Liste mit M Werten 0 Name k HashFunktion Position i M-1 Die Position eines zu sortierenden Namen k in der Liste berechnet man über eine Funktion, HashFunktion genannt. Der in der Liste einzutragenden Name k ist Eingabeparameter der Hashfunktion H. Als Ergebnis liefert die Hash-Funktion die Position i im array, in der der Name zu speichern ist. Die gleiche Funktion H wird benutzt, um die Position eines gesuchten Namen f in der Liste zu bestimmen. Der gesuchte Name f ist dann ebenfalls Eingabeparameter der Hash-Funktion H. Ergebnis von H ist die Position in der Liste, an der der gesuchte Name f steht. Beispiel: Die Liste enthält 10 Datenelemente, also ist M=10. Zu sortieren sind die Namen: Keller, Hulin, Ertel, Gampp Hash-Funktion H(k) ist die Ordnungsnummer des ersten Buchstabens des Namen k modulo M Î Die Hash-Funktion muss immer einen Wert mit dem Modulo-Operator berechnen, damit die berechnete Position i immer innerhalb des array liegt. Zum Einfügen der Namen in die richtige Position wird die Hash-Funktion H(k) wie folgt auf die sortierende Namen angewendet: Programmieren 1 Prof. Dr.-Ing. Silvia Keller Studiengang Angewandte Informatik Ausgabe: 19.03.2004 Seite 105 von 110 Liste mit 10 Werten 0 Gampp H(Keller)= 75 modulo 10 = 5 H(Hulin) = 72 modulo 10 = 2 Hulin H(Ertel) = 69 modulo 10 = 9 H(Gampp) = 71 modulo 10 = 1 Keller 9 7.2 Ertel SUCHEN Bei der Suche nach einem Namen wird ebenfalls die Hash-Funktion verwendet. Ein Suche nach dem Namen Gampp ergibt: H(Gampp) = 71 modulo 10 = 1 An dieser Position steht tatsächlich auch der Name Gampp. Eine Suche nach dem Namen „Brümmer“ ergibt: H(Brümmer) = 66 modulo 10 = 6 An dieser Position ist kein Name gespeichert Ein Vergleich des gesuchten Namens „Brümmer“ mit dem Eintrag in der Liste ergibt jedoch – die Position ist leer. Der Name „Brümmer“ wurde nicht in die Liste eingetragen. 7.3 KOLLISSIONEN Es soll ein weiterer Name „Koch“ in die Liste eingetragen werden. Die Berechnung der Hash-Funktion ergibt: H(Koch) = 75 modulo 10 = 5 An Position 5 ist jedoch schon der Name „Keller“ eingetragen. Die Berechnung des Namens „Koch“ führte zu einer Kollission. Wie kann dieses Problem gelöst werden ? Idee Zur Lösung der Kollission wird versucht für den Namen „Koch“ eine Ausweichposition zu bestimmen. Wenn also Position 5 schon mit dem Namen „Keller“ belegt ist, dann versuchen wir den Namen an die folgende Position, also 6, zu schreiben. In unserem Fall ist die Position 6 frei und damit eine Lösung des Problems. „Koch“ wird also an die Position H(Koch ) + 1 eingetragen. Wäre diese Position jedoch auch belegt, versucht man die nächste folgende Position also H(Koch ) + 2 usw. Programmieren 1 Prof. Dr.-Ing. Silvia Keller Studiengang Angewandte Informatik Ausgabe: 19.03.2004 Seite 106 von 110 Diese Strategie eine Ausweichposition zu finden wird solange angewendet bis entweder ein freier Platz zur Speicherung des Namens gefunden ist oder aber die Liste vollständig ohne Resultat nach freien Positionen durchsucht wurde. Zur Lösung der Kollission wird also eine weitere Funktion angewendet, Kollossions-Funktion genannt. Die oben beschriebene Strategie für die Kollssionsbehandlung wird lineares Sondieren genannt und versucht ausgehend von der berechneten Hash-Position H(Koch ) alle folgenden Positionen in der Liste: (H(k) + i ) modulo M 1 <= i < M Bei der Suche nach dem Namen „Koch“ liefert die Hash-Funktion die Position 5. Da bei jeder durch die Hash-Funktion errechneten Position eine Kollission möglich war, muss ein Vergleich des gesuchten Namens mit dem Namen an der errechneten Position erfolgen. Steht der gesuchte Namen nicht an der errechneten Position, wurde der gesuchte Name, wenn dieser überhaupt in der Liste vorkommt, über eine Kollissionsbehandlung an eine Ausweichposition geschrieben. Also muss auch beim Suchen alle Ausweichpositionen nach dem Namen durchsucht werden. Die Suche endet dann, wenn entweder der gesuchte Name, hier „Koch“, in der Liste gefunden werden konnte, oder aber die errechnete Position frei ist. Im letzten Fall kommt der gesuchte Name nicht in der Liste vor. Im konkreten Beispiel wird zuerst an der errechneten Hash-Position 5 nach Koch gesucht, dann die Ausweichposition 6 berechnet. Hier endte die Suche, da der Eintrag Koch gefunden wurde. 7.4 LÖSCHEN Im obigen Beispiel soll nach Einfügen von „Koch“ der Name „Keller“ aus der Liste gelöscht werden. Die Liste würde nach einem Löschvorgang folgendes Aussehen haben: Liste mit 10 Werten 0 Gampp Hulin Koch 9 Die Position 5 ist nach dem Löschen frei. Wollen wir jetzt nach dem Namen „Koch“ suchen berechnet die Hash-Funktion die Position 5. An der Position 5 steht kein Name mehr, also endet hier die Suche mit dem Ergebnis: Der Name „Koch“ kommt in der Liste nicht vor. Dies ist aber nicht richtig, da Koch an der Position 6 steht. Ertel Das Problem besteht darin, dass Koch vorher über eine Kollission in die Liste eingetragen wurde. Nach dem Löschen von Keller tritt keine Kollssion mehr auf. Wie kann man dieses Problem lösen ? In der Liste wird eine gelöschte Position durch den Eintrag „Hier wurde was gelöscht“ gekennzeichnet. Nach der Berechnung der Hash-Funktion H(Koch) = 5 findet man den Eintrag „ Hier wurde was gelöscht“, d.h. „Koch“ könnte durch eine Kollission an einer anderen Position stehen. Also muss die Kollissionsbehandlung angewendet werden. Entweder man findet über die Kollissionsbehandlung den Namen „Koch“ ( in diesem Beispiel an der Position 6 ) oder aber man trifft auf eine freie Position. Im ersten Fall ist „Koch“ gefunden im zweiten Fall kommt der Name „Koch“ in der Liste tatsächlich nicht vor. Programmieren 1 7.5 Prof. Dr.-Ing. Silvia Keller Studiengang Angewandte Informatik Ausgabe: 19.03.2004 Seite 107 von 110 EIGENSCHAFTEN EINER HASH-FUNKTION Das Hashverfahren arbeitet sehr schnell , wenn 1. Die Hash-Funktion sehr einfach zu berechnen ist 2. als Ergebnis der Hash-Funktion alle möglichen Positionen von 0 bis M-1 in der Liste möglich sind, d.h. die Hash-Funktion ist surjektiv 3. die Hash-Funktion die Dateneelemente in der Liste gut streut 4. möglichst wenig Kollssionen auftreten 7.5.1 Beispiel für übliche Hash-Funktionen Die zu sortierenden Werte werden im Folgenden als Schlüssel bezeichnet. Ein Schlüssel kann entweder eine Zahl oder eine Zeichenfolge sein. 8 Sortiert werden soll eine Zeichenkette mit Anzahl k Zeichen z.B. es sollen Namen sortiert werden k H ( Schlüssel ) = ∑ Ordnungszahl ( Zeicheni ) modulo M i =1 8 Es sollen natürliche Zahlen sortiert werden ( Divisionsmethode ) H(Schlüssel) = Zahl modulo M 8 Es sollen natürliche Zahlen sortiert werden. Die Zahlen werden als Folge von Ziffern znzn-1...z1 interpretiert ( Mittel-Quadrat-Methode ) H ( Schlüssel ) berechnet sich wie folgt: • • 7.5.2 Bilde das Quadrat der Zahl. Der berechnete Wert ist neue Ziffernfolge mit einer Anzahl von Ziffern grösser oder gleich n Entnehme den mitteleren Block von n Ziffern. Diese Ziffern ergeben die Position in der Liste. Beispiele für Kollissions-Funktionen Die zu sortierenden Werte werden im Folgenden als Schlüssel bezeichnet. Ein Schlüssel kann entweder eine Zahl oder eine Zeichenfolge sein. Lineares Sondieren Ausweichposi( Schlüssel ) = ( H(Schlüssel) + i ) modulo M, 1 <= i <= M-1 Quadratisches Sondieren Ausweichposi(Schlüssel ) = ( H(Schlüssel ) +(-) i 2 ) modulo M, 1 <= i <= M-1