From 5bb8b62fa9f87c059a79d4ce2a1e19f99e7eced0 Mon Sep 17 00:00:00 2001 From: Oliver Hofmann Date: Tue, 30 Apr 2024 16:56:01 +0200 Subject: [PATCH 1/3] lecture 5 --- SoSe24/lec03_sort_alg/quick_sort.py | 4 +- SoSe24/lec04_trees/avl_tree.py | 111 ++++++++++++++++++ SoSe24/lec04_trees/avl_tree_plot.py | 29 +++++ SoSe24/lec04_trees/bin_tree.py | 171 ++++++++++++++++++++++++++++ SoSe24/lec04_trees/bin_tree_plot.py | 29 +++++ 5 files changed, 342 insertions(+), 2 deletions(-) create mode 100644 SoSe24/lec04_trees/avl_tree.py create mode 100644 SoSe24/lec04_trees/avl_tree_plot.py create mode 100644 SoSe24/lec04_trees/bin_tree.py create mode 100644 SoSe24/lec04_trees/bin_tree_plot.py diff --git a/SoSe24/lec03_sort_alg/quick_sort.py b/SoSe24/lec03_sort_alg/quick_sort.py index dc87bbf..9cec897 100644 --- a/SoSe24/lec03_sort_alg/quick_sort.py +++ b/SoSe24/lec03_sort_alg/quick_sort.py @@ -54,8 +54,8 @@ def median_pivot(z: AlgoDatArray, left: int, right: int) -> int: def quick_sort(z: AlgoDatArray, left: int, right: int): if left < right: - q = partition(z, left, right) - #q = median_pivot(z, left, right) + #q = partition(z, left, right) + q = median_pivot(z, left, right) quick_sort(z, left, q-1) quick_sort(z, q+1, right) diff --git a/SoSe24/lec04_trees/avl_tree.py b/SoSe24/lec04_trees/avl_tree.py new file mode 100644 index 0000000..b6fd101 --- /dev/null +++ b/SoSe24/lec04_trees/avl_tree.py @@ -0,0 +1,111 @@ +from SoSe24.algodat.foundation import AlgoDatArray, AlgoDatValue, read_int_sequence +from SoSe24.lec04_trees.bin_tree import BinTree, BinTreeNode +from time import perf_counter as pfc + +class AVLTreeNode(BinTreeNode): + def __init__(self, value: AlgoDatValue): + super().__init__(value) + self.parent = None + self.balance = 0 + + def update_balance(self): + left_height = self.left.height() if self.left else 0 + right_height = self.right.height() if self.right else 0 + self.balance = right_height - left_height + + def right_rotate(self) -> BinTreeNode: + new_root = self.left + new_root.parent = self.parent + self.left = new_root.right + if self.left: + self.left.parent = self + new_root.right = self + self.parent = new_root + if new_root.parent: + if new_root.parent.left == self: + new_root.parent.left = new_root + else: + new_root.parent.right = new_root + self.update_balance() + new_root.update_balance() + return new_root + + def left_rotate(self) -> BinTreeNode: + new_root = self.right + new_root.parent = self.parent + self.right = new_root.left + if self.right: + self.right.parent = self + new_root.left = self + self.parent = new_root + if new_root.parent: + if new_root.parent.left == self: + new_root.parent.left = new_root + else: + new_root.parent.right = new_root + self.update_balance() + new_root.update_balance() + return new_root + + def right_left_rotate(self) -> BinTreeNode: + self.right = self.right.right_rotate() + return self.left_rotate() + + def left_right_rotate(self) -> BinTreeNode: + self.left = self.left.left_rotate() + return self.right_rotate() + +class AVLTree(BinTree): + + def new_node(self, value: AlgoDatValue): + return AVLTreeNode(value) + + def balance(self, node: AVLTreeNode): + node.update_balance() + if node.balance == -2: + if node.left.balance <= 0: + node = node.right_rotate() + else: + node = node.left_right_rotate() + elif node.balance == 2: + if node.right.balance >= 0: + node = node.left_rotate() + else: + node = node.right_left_rotate() + if node.parent: + self.balance(node.parent) + else: + self.root = node + + def insert(self, value: AlgoDatValue): + node, parent = super().insert(value) + node.parent = parent + if parent: + self.balance(parent) + return node, parent + + def delete(self, value: AlgoDatValue): + node, parent = super().delete(value) + if node: + node.parent = parent + if parent: + self.balance(parent) + + + +if __name__ == "__main__": + z = read_int_sequence("../../seq0.txt") + print(z, len(z)) + start = pfc() + tree = AVLTree() + for i in z: + tree.insert(i) + tree.walk() + tree.tree_walk() + tree.levelwalk() + #tree.graph_walk() + tree.delete(AlgoDatValue(46)) + tree.delete(AlgoDatValue(48)) + tree.graph_walk() + print(f"Dauer: {pfc() - start:.4f}s") + AlgoDatValue.summary() \ No newline at end of file diff --git a/SoSe24/lec04_trees/avl_tree_plot.py b/SoSe24/lec04_trees/avl_tree_plot.py new file mode 100644 index 0000000..8027a52 --- /dev/null +++ b/SoSe24/lec04_trees/avl_tree_plot.py @@ -0,0 +1,29 @@ +from SoSe24.algodat.foundation import AlgoDatArray, AlgoDatValue, read_int_sequence, read_int_sequence_limited +import matplotlib +matplotlib.use('TkAgg') +import matplotlib.pyplot as plt +import avl_tree as avl + +if __name__ == "__main__": + filename = "../../seq3_sorted.txt" + #filename = "../../seq3.txt" + dummy = read_int_sequence(filename) + n = len(dummy) + step = n // 100 + + memory_values = [] + compare_values = [] + + for right_end in range(1, n, step): + AlgoDatValue.reset() + z = read_int_sequence_limited(filename, right_end) + tree = avl.AVLTree() + for i in z: + tree.insert(i) + memory_values.append(AlgoDatValue.memory) + compare_values.append(AlgoDatValue.compare) + + plt.plot(range(1, n, step), memory_values, 'b', label='Memory') + plt.plot(range(1, n, step), compare_values, 'r', label='Compare') + plt.legend() + plt.show() diff --git a/SoSe24/lec04_trees/bin_tree.py b/SoSe24/lec04_trees/bin_tree.py new file mode 100644 index 0000000..ea089e1 --- /dev/null +++ b/SoSe24/lec04_trees/bin_tree.py @@ -0,0 +1,171 @@ +from SoSe24.algodat.foundation import AlgoDatArray, AlgoDatValue, read_int_sequence +from time import perf_counter as pfc + +class BinTreeNode: + def __init__(self, value: AlgoDatValue): + self.value = value + self.left = None + self.right = None + + def __str__(self): + return f"{self.value}" + + def height(self) -> int: + left_height = self.left.height() if self.left else 0 + right_height = self.right.height() if self.right else 0 + return 1 + max(left_height, right_height) + + + +class BinTree: + def __init__(self): + self.root = None + + def new_node(self, value: AlgoDatValue) -> BinTreeNode: + return BinTreeNode(value) + + def insert(self, value: AlgoDatValue) -> (BinTreeNode, BinTreeNode): + if not self.root: + self.root = self.new_node(value) + return self.root, None + + current = self.root + while True: + if value < current.value: + if current.left: + current = current.left + else: + current.left = self.new_node(value) + return current.left, current + elif value >= current.value: + if current.right: + current = current.right + else: + current.right = self.new_node(value) + return current.right, current + else: + return None, None + + def search(self, value: AlgoDatValue) -> BinTreeNode: + current = self.root + while current: + if value < current.value: + current = current.left + elif value > current.value: + current = current.right + else: + return current + return None + + def delete(self, value: AlgoDatValue): + parent = None + current = self.root + while current: + if value < current.value: + parent = current + current = current.left + elif value > current.value: + parent = current + current = current.right + else: + break + else: + return None, None + + if current.left and current.right: + parent = current + successor = current.right + while successor.left: + parent = successor + successor = successor.left + current.value.value = successor.value.value + current = successor + + if current.left: + child = current.left + else: + child = current.right + + if not parent: + self.root = child + return child, None + elif parent.left == current: + parent.left = child + return child, parent + else: + parent.right = child + return child, parent + + def walk(self): # in-order + print("[ ", end="") + self.walk_recursive(self.root, 0, 0) + print(" ]") + + + def graph_walk(self): + self.leaf_counter = 0 + with open("../../graph.gv", "w") as file: + file.write("digraph BST {\n") + file.write(" node [fontname=\"Arial\"];\n") + self.graph_walk_recursive(self.root, file) + file.write("}") + + def graph_walk_recursive(self, current, file): + if current is not None: + if current.left: + file.write(f"{current.value} -> {current.left.value}; \n") + self.graph_walk_recursive(current.left, file) + else: + file.write(f"left{self.leaf_counter} [shape=point]; \n") + file.write(f"{current.value} -> left{self.leaf_counter}; \n") + self.leaf_counter += 1 + if current.right: + file.write(f"{current.value} -> {current.right.value}; \n") + self.graph_walk_recursive(current.right, file) + else: + file.write(f"right{self.leaf_counter} [shape=point]; \n") + file.write(f"{current.value} -> right{self.leaf_counter}; \n") + self.leaf_counter += 1 + + + def tree_walk(self): + self.walk_recursive(self.root, 0, 1) + + def walk_recursive(self, node: BinTreeNode, level = 0, increase = 1): + if node: + if increase >= 1: + end = "\n" + else: + end = " " + self.walk_recursive(node.left, level+increase, increase) + print(" "*level*3 + str(node.value), end=end) + self.walk_recursive(node.right, level+increase, increase) + + def levelwalk(self): + if self.root is None: + return + queue = [self.root] + while queue: + current = queue.pop(0) + print(current.value, end=" ") + if current.left: + queue.append(current.left) + if current.right: + queue.append(current.right) + print() + + +if __name__ == "__main__": + z = read_int_sequence("../../seq0.txt") + print(z, len(z)) + start = pfc() + tree = BinTree() + for i in z: + tree.insert(i) + tree.walk() + tree.tree_walk() + tree.levelwalk() + tree.delete(AlgoDatValue(46)) + tree.graph_walk() + print(f"Dauer: {pfc() - start:.4f}s") + AlgoDatValue.summary() \ No newline at end of file diff --git a/SoSe24/lec04_trees/bin_tree_plot.py b/SoSe24/lec04_trees/bin_tree_plot.py new file mode 100644 index 0000000..d9f3225 --- /dev/null +++ b/SoSe24/lec04_trees/bin_tree_plot.py @@ -0,0 +1,29 @@ +from SoSe24.algodat.foundation import AlgoDatArray, AlgoDatValue, read_int_sequence, read_int_sequence_limited +import matplotlib +matplotlib.use('TkAgg') +import matplotlib.pyplot as plt +import bin_tree as bt + +if __name__ == "__main__": + filename = "../../seq3_sorted.txt" + #filename = "../../seq3.txt" + dummy = read_int_sequence(filename) + n = len(dummy) + step = n // 100 + + memory_values = [] + compare_values = [] + + for right_end in range(1, n, step): + AlgoDatValue.reset() + z = read_int_sequence_limited(filename, right_end) + tree = bt.BinTree() + for i in z: + tree.insert(i) + memory_values.append(AlgoDatValue.memory) + compare_values.append(AlgoDatValue.compare) + + plt.plot(range(1, n, step), memory_values, 'b', label='Memory') + plt.plot(range(1, n, step), compare_values, 'r', label='Compare') + plt.legend() + plt.show() From 3a792644cfe1b31ea2991995c50b306f81af2530 Mon Sep 17 00:00:00 2001 From: hofmannol Date: Tue, 7 May 2024 15:40:35 +0200 Subject: [PATCH 2/3] Lecture 5 --- SoSe24/lec04_trees/avl_tree.py | 5 +- SoSe24/lec04_trees/b_tree.py | 134 ++++++++++++++++++++++++++++ SoSe24/lec04_trees/bin_tree.py | 4 +- SoSe24/lec04_trees/bin_tree_plot.py | 1 + 4 files changed, 140 insertions(+), 4 deletions(-) create mode 100644 SoSe24/lec04_trees/b_tree.py diff --git a/SoSe24/lec04_trees/avl_tree.py b/SoSe24/lec04_trees/avl_tree.py index b6fd101..89fdd52 100644 --- a/SoSe24/lec04_trees/avl_tree.py +++ b/SoSe24/lec04_trees/avl_tree.py @@ -2,6 +2,7 @@ from SoSe24.algodat.foundation import AlgoDatArray, AlgoDatValue, read_int_seque from SoSe24.lec04_trees.bin_tree import BinTree, BinTreeNode from time import perf_counter as pfc + class AVLTreeNode(BinTreeNode): def __init__(self, value: AlgoDatValue): super().__init__(value) @@ -103,9 +104,9 @@ if __name__ == "__main__": tree.walk() tree.tree_walk() tree.levelwalk() - #tree.graph_walk() + tree.graph_walk() tree.delete(AlgoDatValue(46)) tree.delete(AlgoDatValue(48)) - tree.graph_walk() + #tree.graph_walk() print(f"Dauer: {pfc() - start:.4f}s") AlgoDatValue.summary() \ No newline at end of file diff --git a/SoSe24/lec04_trees/b_tree.py b/SoSe24/lec04_trees/b_tree.py new file mode 100644 index 0000000..a1934b4 --- /dev/null +++ b/SoSe24/lec04_trees/b_tree.py @@ -0,0 +1,134 @@ +from SoSe24.algodat.foundation import AlgoDatArray, AlgoDatValue, read_int_sequence +from time import perf_counter as pfc + + +class BTreeNode: + def __init__(self, m: int): + self.n = 0 + self.leaf = True + self.keys = AlgoDatArray(2 * m - 1) + self.children = [None] * (2 * m) + + def __str__(self): + return "(" + " ".join([str(self.keys[i]) for i in range(self.n)]) + ")" + + +class BTree: + def __init__(self, m: int): + self.m = m + self.root = BTreeNode(m) + + def search(self, key: AlgoDatValue, start: BTreeNode = None) -> BTreeNode: + if not start: + start = self.root + i = 0 + while i < start.n and key > start.keys[i]: + i += 1 + if i < start.n and key == start.keys[i]: + return start + if start.leaf: + return None + return self.search(key, start.children[i]) + + def split_child(self, parent: BTreeNode, i: int): + child = parent.children[i] + h = BTreeNode(self.m) + h.leaf = child.leaf + h.n = self.m - 1 + for j in range(self.m - 1): + h.keys[j] = child.keys[j + self.m] + if not h.leaf: + for j in range(self.m): + h.children[j] = child.children[j + self.m] + for j in range(self.m, child.n + 1): + child.children[j] = None + child.n = self.m - 1 + for j in range(parent.n, i, -1): + parent.children[j + 1] = parent.children[j] + parent.keys[j] = parent.keys[j - 1] + parent.children[i + 1] = h + parent.keys[i] = child.keys[self.m - 1] + parent.n += 1 + + def insert(self, k: AlgoDatValue): + r = self.root + if r.n == 2 * self.m - 1: + h = BTreeNode(self.m) + self.root = h + h.leaf = False + h.n = 0 + h.children[0] = r + self.split_child(h, 0) + self.insert_in_node(h, k) + else: + self.insert_in_node(r, k) + + def insert_in_node(self, start: BTreeNode, k: AlgoDatValue): + i = start.n + if start.leaf: + while i >= 1 and k < start.keys[i-1]: + start.keys[i] = start.keys[i-1] + i -= 1 + start.keys[i] = k + start.n += 1 + else: + j = 0 + while j < start.n and k > start.keys[j]: + j += 1 + if start.children[j].n == 2 * self.m - 1: + self.split_child(start, j) + if k > start.keys[j]: + j += 1 + self.insert_in_node(start.children[j], k) + + def walk(self, start: BTreeNode = None): + if not start: + start = self.root + i = 0 + while i < start.n: + if not start.leaf: + self.walk(start.children[i]) + print(start.keys[i], end=" ") + i += 1 + if not start.leaf: + self.walk(start.children[i]) + + def height(self, start: BTreeNode = None): + if not start: + start = self.root + if start.leaf: + return 0 + return 1 + self.height(start.children[0]) + + def graph_walk(self): + queue = [ self.root ] + with open("../../btree.gv", "w") as file: + file.write("digraph BTree {\n") + file.write(" node [fontname=\"Arial\"];\n") + while queue: + current = queue.pop(0) + p = str(current) + file.write(f'"{p}"; \n') + i = 0 + while i <= current.n: + if not current.leaf: + queue.append(current.children[i]) + c = str(current.children[i]) + file.write(f'"{p}" -> "{c}";\n') + i += 1 + file.write("}") + + +if __name__ == "__main__": + z = read_int_sequence("../../seq2.txt") + start = pfc() + tree = BTree(3) + for i in z: + tree.insert(i) + print(f"Height: {tree.height()}") + tree.walk() + tree.graph_walk() + s = tree.search(AlgoDatValue(0)) + print(f"\nKnoten mit 0: {str(s)}") + print(f"Dauer: {pfc() - start:.4f}s") + AlgoDatValue.summary() \ No newline at end of file diff --git a/SoSe24/lec04_trees/bin_tree.py b/SoSe24/lec04_trees/bin_tree.py index ea089e1..589e04a 100644 --- a/SoSe24/lec04_trees/bin_tree.py +++ b/SoSe24/lec04_trees/bin_tree.py @@ -64,13 +64,13 @@ class BinTree: if value < current.value: parent = current current = current.left - elif value > current.value: + elif value >= current.value: parent = current current = current.right else: break else: - return None, None + return if current.left and current.right: parent = current diff --git a/SoSe24/lec04_trees/bin_tree_plot.py b/SoSe24/lec04_trees/bin_tree_plot.py index d9f3225..300de7d 100644 --- a/SoSe24/lec04_trees/bin_tree_plot.py +++ b/SoSe24/lec04_trees/bin_tree_plot.py @@ -22,6 +22,7 @@ if __name__ == "__main__": tree.insert(i) memory_values.append(AlgoDatValue.memory) compare_values.append(AlgoDatValue.compare) + print(right_end, AlgoDatValue.compare) plt.plot(range(1, n, step), memory_values, 'b', label='Memory') plt.plot(range(1, n, step), compare_values, 'r', label='Compare') From 2c98bb546d8670a89c0b4f0cf9f107d84a0b5995 Mon Sep 17 00:00:00 2001 From: hofmannol Date: Tue, 14 May 2024 16:54:25 +0200 Subject: [PATCH 3/3] Lecture 6 --- SoSe24/lec05_hash/hash_plot.py | 31 ++++++++++ SoSe24/lec05_hash/hash_table.py | 101 ++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 SoSe24/lec05_hash/hash_plot.py create mode 100644 SoSe24/lec05_hash/hash_table.py diff --git a/SoSe24/lec05_hash/hash_plot.py b/SoSe24/lec05_hash/hash_plot.py new file mode 100644 index 0000000..3a6ac04 --- /dev/null +++ b/SoSe24/lec05_hash/hash_plot.py @@ -0,0 +1,31 @@ +from SoSe24.algodat.foundation import AlgoDatArray, AlgoDatValue, read_int_sequence, read_int_sequence_limited +import matplotlib +import matplotlib.pyplot as plt +import hash_table as ht + +if __name__ == "__main__": + filename = "../../seq3.txt" + dummy = read_int_sequence(filename) + n = len(dummy) + step = n // 100 + + memory_values = [] + compare_values = [] + alpha_values = [] + + for right_end in range(1, n, step): + AlgoDatValue.reset() + z = read_int_sequence_limited(filename, right_end) + hash = ht.HashTable(int(right_end*2), hash_function=ht.h, exploratory_function=ht.f1) + for i in z: + hash.insert(i) + memory_values.append(AlgoDatValue.memory) + compare_values.append(AlgoDatValue.compare) + alpha_values.append(hash.alpha()) + + plt.plot(range(1, n, step), memory_values, 'b', label='Memory') + plt.plot(range(1, n, step), compare_values, 'r', label='Compare') + plt.plot(range(1, n, step), alpha_values, 'g', label='Alpha') + + plt.legend() + plt.show() diff --git a/SoSe24/lec05_hash/hash_table.py b/SoSe24/lec05_hash/hash_table.py new file mode 100644 index 0000000..87e5521 --- /dev/null +++ b/SoSe24/lec05_hash/hash_table.py @@ -0,0 +1,101 @@ +from SoSe24.algodat.foundation import AlgoDatArray, AlgoDatValue, read_int_sequence, MinusInf +from time import perf_counter as pfc + +#Goldener Schnitt +import math +a = (math.sqrt(5) - 1) / 2 +explore_steps = 0 + +def h(x, m): + return int(x*a - int(x*a) * m) + + +def f(x, i, m): + return (h(x, m) + i + 14*i*i) % m + + +def f1(x, i, m): + if i % 2 == 0: + return (h(x, m) + i*i) % m + return ((h(x, m) - i*i) % m + m) % m + + +class HashTable: + def __init__(self, m, hash_function, exploratory_function=None): + self.m = m + self.h = hash_function + self.f = exploratory_function + self.n = 0 + self.table = AlgoDatArray(m) + + def insert(self, x): + global explore_steps + i = 0 + while i < self.m: + j = self.f(x.value, i, self.m) + if self.is_free(j): + self.table[j].value = x.value + self.n += 1 + return True + i += 1 + explore_steps += 1 + return False + + def search(self, x): + global explore_steps + i = 0 + while i < self.m: + j = f(x, i, self.m) + if self.table[j] == x: + return True + if self.table[j] == None: + return False + i += 1 + explore_steps += 1 + return False + + def delete(self, x): + global explore_steps + i = 0 + while i < self.m: + j = f(x, i, self.m) + if self.table[j].value == x: + self.table[j].value = "DELETED" + self.n -= 1 + return True + if self.table[j].value is None: + return False + i += 1 + explore_steps += 1 + return False + + def __str__(self): + return str(self.table) + + def alpha(self): + return self.n / self.m + + def is_free(self, i): + if self.table[i] == None: + return True + if self.table[i] == "DELETED": + return True + return False + + +if __name__ == "__main__": + z = read_int_sequence("../../seq1.txt") + start = pfc() + hash = HashTable(31, h, f) + for algodat_value in z: + hash.insert(algodat_value) + print(hash) + print(f"Alpha: {hash.alpha()}") + hash.delete(11) + hash.search(47) + hash.search(243) + print(hash) + print(f"Alpha: {hash.alpha()}") + print(f"Dauer: {pfc() - start:.4f}s") + print(f"Sondierungsschritte: {explore_steps}") + AlgoDatValue.summary() \ No newline at end of file