From 9a7abc222e97caac4036db96ae894c93b471be27 Mon Sep 17 00:00:00 2001 From: Peter Gerwinski <peter.gerwinski@hs-bochum.de> Date: Thu, 28 Apr 2022 15:18:43 +0200 Subject: [PATCH] Beispiele und Notizen 28.4.2022: Hash-Tabelle --- 20220428/ad-20220428.txt | 16 +++++++++ 20220428/hash-map-7.c | 73 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 20220428/ad-20220428.txt create mode 100644 20220428/hash-map-7.c diff --git a/20220428/ad-20220428.txt b/20220428/ad-20220428.txt new file mode 100644 index 0000000..b60ebc8 --- /dev/null +++ b/20220428/ad-20220428.txt @@ -0,0 +1,16 @@ +Wie lösen wir das Problem der Speicherineffizienz? + + - "zu große" Hash-Funktion wählen, danach modulo einer "krummen" Zahl rechnen, + typischerweise eine Primzahl + + - Programm "gperf": + Die Wörter sind vorher bekannt. (Sonst nicht einsetzbar.) + Das Programm erzeugt eine "perfekte" Hash-Tabelle (d.h. ohne Kollisionen). + Einsatz in gcc und verwandten Compilern zur Erkennung von Schlüsselwörtern + + - Ansonsten: Kollisionsbehandlung + - z.B.: wenn Stelle bereits besetzt, weiterwnadern, freie Stelle finden + (z.B.: "sieben" bei 't' statt bei 's' speichern) + - oder: an jeder Stelle eine verkettete Liste von Möglichkeiten (dort: O(n)) + - oder: an jeder Stelle eine weitere Hash-Tabelle + siehe: https://de.wikipedia.org/wiki/Hashtabelle diff --git a/20220428/hash-map-7.c b/20220428/hash-map-7.c new file mode 100644 index 0000000..e3161f5 --- /dev/null +++ b/20220428/hash-map-7.c @@ -0,0 +1,73 @@ +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +int n[65536]; /* zunächst: alle 0 */ +const char *check[65536]; /* zunächst: alle NULL */ + +uint16_t hash (const char *name) +{ + if (name && name[0]) + { + uint8_t first_char = name[0]; + uint8_t second_char = name[1]; + return first_char + 256 * second_char; + } + else + return 0; +} + +void put_number (const char *name, int value) +{ + /* Nimm die ersten 2 Zeichen des Strings, + * berechne daraus einen Array-Index von 0 bis 65535. + * Dort hinterlege die Zahl "value" im Array. + */ + int i = hash (name); + n[i] = value; + check[i] = name; /* Funktioniert so bei String-Konstanten. Ansonsten: String kopieren. */ +} + +int get_number (const char *name) /* nicht mehr geschummelt, O(1), aber: */ +{ /* - Speicher-ineffizient */ + int value = -1; + /* Nimm die ersten 2 Zeichen des Strings, + * berechne daraus einen Array-Index von 0 bis 65535. + * Dort entnimm die Zahl "value". + */ + int i = hash (name); + if (!strcmp (name, check[i])) + value = n[i]; + return value; +} + +void debug_hash_table () +{ + for (int i = 0; i < 65536; i++) + if (n[i]) + printf ("%04x %2d %s\n", i, n[i], check[i]); +} + +int main (void) +{ + put_number ("eins", 1); + put_number ("zwei", 2); + put_number ("drei", 3); + put_number ("vier", 4); + put_number ("fünf", 5); + put_number ("sechs", 6); + put_number ("sieben", 7); + put_number ("acht", 8); + put_number ("neun", 9); + put_number ("zehn", 10); + debug_hash_table (); + int eins = get_number ("eins"); + int zwei = get_number ("zwei"); + int drei = get_number ("drei"); + int vier = get_number ("vier"); + int fuenf = get_number ("fünf"); + int sechs = get_number ("sechs"); + int sieben = get_number ("sieben"); + printf ("%d %d %d %d %d %d %d\n", eins, zwei, drei, vier, fuenf, sechs, sieben); + return 0; +} -- GitLab