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