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()