From c8a4038795717fcf299536bc8b6b6982bb3ecc4c Mon Sep 17 00:00:00 2001 From: Oliver Hofmann Date: Tue, 13 May 2025 13:00:07 +0200 Subject: [PATCH 1/2] Hashtable added --- praktika/07_hashtable/praktikum.py | 124 +++++++++++++++++++ vorlesung/L07_hashtable/__init__.py | 0 vorlesung/L07_hashtable/analyze_hashtable.py | 60 +++++++++ vorlesung/L07_hashtable/hashtable.py | 76 ++++++++++++ 4 files changed, 260 insertions(+) create mode 100644 praktika/07_hashtable/praktikum.py create mode 100644 vorlesung/L07_hashtable/__init__.py create mode 100644 vorlesung/L07_hashtable/analyze_hashtable.py create mode 100644 vorlesung/L07_hashtable/hashtable.py diff --git a/praktika/07_hashtable/praktikum.py b/praktika/07_hashtable/praktikum.py new file mode 100644 index 0000000..883d094 --- /dev/null +++ b/praktika/07_hashtable/praktikum.py @@ -0,0 +1,124 @@ +import math +import unittest +from utils.literal import Literal +from utils.memory_cell import MemoryCell +from utils.memory_array import MemoryArray +from vorlesung.L07_hashtable.hashtable import HashTableOpenAddressing + +#Goldener Schnitt +a = Literal((math.sqrt(5) - 1) / 2) + +# Hashfunktion nach multiplikativer Methode +def h(x: MemoryCell, m: Literal) -> Literal: + with MemoryCell(int(x * a)) as integer_part, MemoryCell(x * a) as full_product: + with MemoryCell(full_product - integer_part) as fractional_part: + return Literal(abs(int(fractional_part * m))) + +# Quadratische Sondierung +def f(x: MemoryCell, i: Literal, m: Literal) -> Literal: + c1 = 1 + c2 = 5 + with MemoryCell(h(x, m)) as initial_hash, MemoryCell(c2 * int(i) * int(i)) as quadratic_offset: + with MemoryCell(initial_hash + quadratic_offset) as probe_position: + probe_position += Literal(c1 * int(i)) # Linear component + return probe_position % m + +# Symmetrische quadratische Sondierung +def fs(x: MemoryCell, i: Literal, m: Literal) -> Literal: + with MemoryCell(h(x, m)) as base_hash, MemoryCell(int(i) * int(i)) as square: + if int(i) % 2 == 0: # gerades i: Vorwärtssondierung + with MemoryCell(base_hash + square) as position: + return position % m + else: # ungerades i: Rückwärtssondierung + with MemoryCell(base_hash - square) as position: + return position % m + + +class TestHashTableOpenAddressing(unittest.TestCase): + + def test_hash_function(self): + x = MemoryCell(22) + m = Literal(20) + self.assertEqual(11, h(x, m).value) + + def test_probe_function(self): + x = MemoryCell(22) + i = Literal(0) + m = Literal(20) + self.assertEqual(11, f(x, i, m).value) + i = Literal(1) + self.assertEqual(17, f(x, i, m).value) + i = Literal(2) + self.assertEqual(13, f(x, i, m).value) + + + +if __name__ == "__main__": + #unittest.main() + + print("*** Aufgabe 3 ***") + size = Literal(20) + print(f"Anlage einer Hash-Tabelle mit offener Adressierung mit Größe {size}") + ht = HashTableOpenAddressing(size, f) + print("Einfügen der Werte aus seq0.txt") + for cell in MemoryArray.create_array_from_file("data/seq0.txt"): + if not ht.insert(cell): + print(f"Einfügen von {cell} nicht möglich") + print(ht) + print(f"Belegungsfaktor: {ht.alpha()}") + + with MemoryCell(52) as cell: + print(f"Suche nach {cell}") + if ht.search(cell): + print(f"{cell} gefunden, wird gelöscht.") + ht.delete(cell) + else: + print(f"{cell} nicht gefunden") + print(ht) + print(f"Belegungsfaktor: {ht.alpha()}") + print("Einfügen von 24") + with MemoryCell(24) as cell: + if not ht.insert(cell): + print(f"Einfügen von {cell} nicht möglich") + print(ht) + print(f"Belegungsfaktor: {ht.alpha()}") + print() + + print("*** Aufgabe 4 ***") + size = Literal(90) + print(f"Anlage einer Hash-Tabelle mit offener Adressierung mit Größe {size}") + ht = HashTableOpenAddressing(size, f) + print("Einfügen der Werte aus seq1.txt") + for cell in MemoryArray.create_array_from_file("data/seq1.txt"): + if not ht.insert(cell): + print(f"Einfügen von {cell} nicht möglich") + print(ht) + print(f"Belegungsfaktor: {ht.alpha()}") + print() + + print("*** Aufgabe 5 ***") + size = Literal(89) + print(f"Anlage einer Hash-Tabelle mit offener Adressierung mit Größe {size}") + ht = HashTableOpenAddressing(size, f) + print("Einfügen der Werte aus seq1.txt") + for cell in MemoryArray.create_array_from_file("data/seq1.txt"): + if not ht.insert(cell): + print(f"Einfügen von {cell} nicht möglich") + print(ht) + print(f"Belegungsfaktor: {ht.alpha()}") + print() + + print("*** Aufgabe 6 ***") + size = Literal(90) + print(f"Anlage einer Hash-Tabelle mit offener Adressierung mit Größe {size}") + print("Verwendung der symmetrischen quadratischen Sondierung") + ht = HashTableOpenAddressing(size, fs) + print("Einfügen der Werte aus seq1.txt") + for cell in MemoryArray.create_array_from_file("data/seq1.txt"): + if not ht.insert(cell): + print(f"Einfügen von {cell} nicht möglich") + print(ht) + print(f"Belegungsfaktor: {ht.alpha()}") + print() + + diff --git a/vorlesung/L07_hashtable/__init__.py b/vorlesung/L07_hashtable/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vorlesung/L07_hashtable/analyze_hashtable.py b/vorlesung/L07_hashtable/analyze_hashtable.py new file mode 100644 index 0000000..441d1bb --- /dev/null +++ b/vorlesung/L07_hashtable/analyze_hashtable.py @@ -0,0 +1,60 @@ +import math +import random +from utils.literal import Literal +from utils.memory_cell import MemoryCell +from utils.memory_array import MemoryArray +from utils.memory_manager import MemoryManager +from vorlesung.L07_hashtable.hashtable import HashTableOpenAddressing + +#Goldener Schnitt +a = Literal((math.sqrt(5) - 1) / 2) + +# Hashfunktion nach multiplikativer Methode +def h(x: MemoryCell, m: Literal) -> Literal: + with MemoryCell(int(x * a)) as integer_part, MemoryCell(x * a) as full_product: + with MemoryCell(full_product - integer_part) as fractional_part: + return Literal(abs(int(fractional_part * m))) + +# Quadratische Sondierung +def f(x: MemoryCell, i: Literal, m: Literal) -> Literal: + c1 = 1 + c2 = 5 + with MemoryCell(h(x, m)) as initial_hash, MemoryCell(c2 * int(i) * int(i)) as quadratic_offset: + with MemoryCell(initial_hash + quadratic_offset) as probe_position: + probe_position += Literal(c1 * int(i)) # Linear component + return probe_position % m + +# Symmetrische quadratische Sondierung +def fs(x: MemoryCell, i: Literal, m: Literal) -> Literal: + with MemoryCell(h(x, m)) as base_hash, MemoryCell(int(i) * int(i)) as square: + if int(i) % 2 == 0: # gerades i: Vorwärtssondierung + with MemoryCell(base_hash + square) as position: + return position % m + else: # ungerades i: Rückwärtssondierung + with MemoryCell(base_hash - square) as position: + return position % m + + +def analyze_complexity(sizes): + """ + Analysiert die Komplexität + + :param sizes: Eine Liste von Eingabegrößen für die Analyse. + """ + for size in sizes: + MemoryManager.purge() # Speicher zurücksetzen + ht = HashTableOpenAddressing(size, f) + random_array = MemoryArray.create_random_array(size, -100, 100) + for cell in random_array: + ht.insert(cell) + MemoryManager.reset() + cell = random.choice(random_array.cells) + ht.search(cell) + MemoryManager.save_stats(size) + + MemoryManager.plot_stats(["cells", "compares"]) + + +if __name__ == "__main__": + sizes = range(1, 1001, 10) + analyze_complexity(sizes) diff --git a/vorlesung/L07_hashtable/hashtable.py b/vorlesung/L07_hashtable/hashtable.py new file mode 100644 index 0000000..d2b7abd --- /dev/null +++ b/vorlesung/L07_hashtable/hashtable.py @@ -0,0 +1,76 @@ +from collections.abc import Callable +from utils.literal import Literal +from utils.memory_array import MemoryArray +from utils.memory_cell import MemoryCell +from utils.memory_range import mrange + + +UNUSED_MARK = "UNUSED" +DELETED_MARK = "DELETED" + +class HashTableOpenAddressing: + def __init__(self, m: Literal, f: Callable[[MemoryCell, Literal, Literal], Literal]): + if not isinstance(m, Literal): + m = Literal(m) + self.m = m + self.f = f + self.table = MemoryArray(m) + for i in mrange(m): + self.table[i].value = UNUSED_MARK + + def insert(self, x: MemoryCell): + with MemoryCell(0) as i: + while i < self.m: + j = self.f(x, i, self.m) + if self.is_free(j): + self.table[j].set(x) + return True + i.set(i.succ()) + return False + + def search(self, x: MemoryCell): + with MemoryCell(0) as i: + while i < self.m: + j = self.f(x, i, self.m) + if self.is_unused(j): + return False + if self.table[j] == x: + return True + i.set(i.succ()) + return False + + def delete(self, x: MemoryCell): + with MemoryCell(0) as i: + while i < self.m: + j = self.f(x, i, self.m) + if self.is_unused(j): + return False + if self.table[j] == x: + self.table[j].value = DELETED_MARK + return True + i.set(i.succ()) + return False + + def __str__(self): + return str(self.table) + + def alpha(self): + with MemoryCell(0) as i: + used = 0 + while i < self.m: + used += 0 if self.is_free(i) else 1 + i.set(i.succ()) + return used / int(self.m) + + def is_unused(self, i: Literal): + if self.table[i].value == UNUSED_MARK: + return True + return False + + def is_deleted(self, i: Literal): + if self.table[i].value == DELETED_MARK: + return True + return False + + def is_free(self, i: Literal): + return self.is_unused(i) or self.is_deleted(i) From f62cc0a1c8adaf1b936d7c15a23c85dbc0d51bb5 Mon Sep 17 00:00:00 2001 From: Oliver Hofmann Date: Wed, 21 May 2025 06:13:36 +0200 Subject: [PATCH 2/2] =?UTF-8?q?H=C3=B6hle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/hoehle.txt | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 data/hoehle.txt diff --git a/data/hoehle.txt b/data/hoehle.txt new file mode 100644 index 0000000..5b08cd4 --- /dev/null +++ b/data/hoehle.txt @@ -0,0 +1,8 @@ +"Höhleneingang" <> "Ost/West-Passage" +"Höhleneingang" <> "Nord/Süd-Passage" +"Nord/Süd-Passage" <> "Nebelraum" +"Steiniger Pfad" > "Ost/West-Passage" +"Ost/West-Passage" <> "Schwefelgewölbe" +"Schwefelgewölbe" > "Steiniger Pfad" +"Schatzkammer" > "Nebelraum" +"Steiniger Pfad" > "Schatzkammer" \ No newline at end of file