Anfang Vorherige Seite Nächste Seite Ende Inhalt

... und mit einer Hashmap

Um die Wörter eines Textes schneller zu zählen, kann man sich eine eigene Hashmap erstellen. Hier enthält jeder Knoten eine Zeiger auf ein Wort, die Häufigkeit des Auftretens in dem Text und einen Zeiger auf den nächsten Knoten in der Hashmap. Das folgende Beispiel zeigt, wie die Hashmap aussieht, für den Fall, daß einmal das Wort 'und' und zweimal das Wort 'in' eingefügt worden sind. Die Wörter haben in diesem Beispiel den gleichen Hashwert.

Hashmap

typedef struct node *nodeptr;
typedef struct node {
    char *word;
    int count;
    nodeptr next;
} node;

Die C-Struktur stellt nur die nötigsten Angaben für die Hashtabelle bereit. Das ist ein Zeiger auf des Wort, die Auftrittshäufigkeit und einen Zeiger auf den nächsten Knoten.

unsigned int hash(char *p) {
    unsigned int h = 0;
    for ( ; *p; p++)
          h = MULT * h + *p;
    return h % NHASH;
}

Die Hashfunktion ordnet jedem Wort eine postive Zahl größer als NHASH zu. NHASH gibt die Größe der Hashtabelle an. Idealerweise ist dies eine Primzahl, die etwas größer ist, als die Anzahl der verschiedenen Wörter, die in dem Text auftreten.

void incword(char *s)
    h = hash(s)
    for (p = bin[h]; p != NULL; p = p->next)
          if (strcmp(s, p->word) == 0
            (p->count)++
            return
    p = malloc(sizeof(hashnode))
    p->count = 1
    p->word = malloc(strlen(s)+1)
    strcpy(p->word, s)
    p->next = bin[h]
    bin[h] = p

Diese Funktion leistet eigentlich den größten Teil der Arbeit. Sie läßt zuerst den Hashwert des Wortes berechnen. Dann wird jedes Wort, daß den gleichen Hashwert besitzt mit der Eingabe verglichen. Falls das Wort schon in der Hashtabelle enthalten sein sollte, wird einfach der Zähler erhöht. Gibt es noch keine Knoten für diese Wort, dann wird ein neuer erstellt, Speicherplatz bereitgestellt, eine Kopie des Wortes angelegt und schließlich am Anfang der Liste eingefügt.

int main()
    for (i = 0; i < NHASH; i++)
          bin[i] = NULL
    while (scanf("%s", buf) != EOF)
          incword(buf)
    for (i = 0; i < NHASH; i++)
          for (p = bin[i]; p != NULL; p = p->next)
            printf p->word, p->count
    return 0

Die main()-Funktion stellt sicher, daß die Hashtabelle noch nicht gefüllt ist. Sie liest dann die Eingabe ein und übergibt sie an die Funktion incword(). Am Ende wird die Ausgabe bereitgestellt.

Die Erstellung der Wortliste dauert nur noch ca. 1.22 Sekunden. (0.80 lesen, 0.33 einfügen, 0.09 schreiben) und ist somit ca. 7.77 Sekunden schneller.


Anfang Vorherige Seite Nächste Seite Ende Inhalt