diff --git a/.idea/AlgoDatSoSe25.iml b/.idea/AlgoDatSoSe25.iml index 982282a..bf024fa 100644 --- a/.idea/AlgoDatSoSe25.iml +++ b/.idea/AlgoDatSoSe25.iml @@ -5,7 +5,7 @@ - + \ No newline at end of file diff --git a/praktika/03_quick_and_heap/priority_queue.py b/praktika/03_quick_and_heap/priority_queue.py new file mode 100644 index 0000000..0dc6161 --- /dev/null +++ b/praktika/03_quick_and_heap/priority_queue.py @@ -0,0 +1,150 @@ +from utils.memory_array import MemoryArray +from utils.memory_cell import MemoryCell +from utils.memory_manager import MemoryManager +from utils.literal import Literal +import random + +class PriorityQueue: + + def __init__(self, size: Literal): + self.items = MemoryArray(size) + self.heapsize = MemoryCell(0) + + def __len__(self): + return self.heapsize.value + + def insert(self, item: MemoryCell): + if self.heapsize == self.items.length(): + raise Exception("Queue is full") + self.heapsize.set(self.heapsize.succ()) + self.items[adjust_index(self.heapsize)].set(item.value) + heapyfy_up(self.items, self.heapsize) + + + def pop(self) -> MemoryCell | None: + if self.is_empty(): + return None + result = MemoryCell(self.items[Literal(0)]) + self.heapsize.set(self.heapsize.pred()) + if self.heapsize > Literal(1): + swap(self.items, 0, int(self.heapsize)) + max_heapyfy(self.items, Literal(1), self.heapsize) + return result + + def peek(self) -> MemoryCell | None: + if self.is_empty(): + return None + return MemoryCell(self.items[Literal(0)]) + + def is_empty(self) -> bool: + return self.heapsize == Literal(0) + + def __str__(self): + result = "[ " + for i, cell in enumerate(self.items.cells): + if i == int(self.heapsize): + result += "| " + result += str(cell) + " " + result += "]" + return result + +def left_child(i: Literal): + return Literal(2 * int(i)) + + +def right_child(i: Literal): + return Literal(2 * int(i) + 1) + + +def adjust_index(i: Literal): + return i.pred() + +def heapyfy_up(z: MemoryArray, i: Literal): + if i == Literal(1): + return + parent = Literal(int(i) // 2) + if z[adjust_index(parent)] >= z[adjust_index(i)]: + return + swap(z, int(i)-1, int(parent)-1) + heapyfy_up(z, parent) + + +def max_heapyfy(z: MemoryArray, i: Literal, heapsize: Literal): + l = left_child(i) + r = right_child(i) + with MemoryCell(i) as max_value: + if l <= heapsize and z[adjust_index(l)] > z[adjust_index(i)]: + max_value.set(l) + if r <= heapsize and z[adjust_index(r)] > z[adjust_index(max_value)]: + max_value.set(r) + if max_value != i: + swap(z, int(i)-1, int(max_value)-1) + max_heapyfy(z, max_value, heapsize) + + +def swap(z: MemoryArray, i: int, j: int): + tmp = z[Literal(i)].value + z[Literal(i)] = z[Literal(j)] + z[Literal(j)].set(tmp) + + +def analyze_complexity_insert(sizes, presorted=False): + """ + Analysiert die Komplexität der Insert-Funktion. + """ + for size in sizes: + MemoryManager().purge() # Speicher zurücksetzen + pq = PriorityQueue(Literal(size)) + insert_list = [random.randint(-100, 100) for _ in range(size)] + if presorted: + insert_list.sort() + for insert_value in insert_list[:-1]: + pq.insert(MemoryCell(insert_value)) + MemoryManager().reset() + pq.insert(MemoryCell(insert_list[-1])) + MemoryManager.save_stats(size) + + MemoryManager.plot_stats(["cells", "compares", "writes"]) + + +def analyze_complexity_pop(sizes, presorted=False): + """ + Analysiert die Komplexität der Pop-Funktion. + """ + for size in sizes: + MemoryManager().purge() # Speicher zurücksetzen + pq = PriorityQueue(Literal(size)) + insert_list = [random.randint(-100, 100) for _ in range(size)] + if presorted: + insert_list.sort() + for insert_value in insert_list: + pq.insert(MemoryCell(insert_value)) + MemoryManager().reset() + pq.pop() + MemoryManager.save_stats(size) + + MemoryManager.plot_stats(["cells", "compares", "writes"]) + + +if __name__ == '__main__': + length = Literal(10) + pq = PriorityQueue(length) + for i in range(10): + space_left = int(length) - len(pq) + if space_left > 0: + insert_count = random.randint(1, space_left) + insert_sequence = [random.randint(1, int(length)) for _ in range(insert_count)] + print(f"-> {insert_sequence}") + for j in insert_sequence: + pq.insert(MemoryCell(j)) + print(f"{pq}") + if not pq.is_empty(): + pop_count = random.randint(1, len(pq)) + output_sequence = [int(pq.pop()) for _ in range(pop_count)] + print(f"<- {output_sequence}") + print(f"{pq}") + + sizes = range(10, 501, 5) + analyze_complexity_insert(sizes, presorted=True) + analyze_complexity_pop(sizes, presorted=True) + diff --git a/praktika/03_quick_and_heap/quick_sorting_enhanced.py b/praktika/03_quick_and_heap/quick_sorting_enhanced.py new file mode 100644 index 0000000..6690a86 --- /dev/null +++ b/praktika/03_quick_and_heap/quick_sorting_enhanced.py @@ -0,0 +1,93 @@ +from utils.memory_array import MemoryArray +from utils.memory_cell import MemoryCell +from utils.memory_manager import MemoryManager +from utils.literal import Literal + +def quick_sort_stepwise(z: MemoryArray, l: Literal, r: Literal): + if l < r: + q = partition(z, l, r) + yield z + yield from quick_sort_stepwise(z, l, q.pred()) + yield from quick_sort_stepwise(z, q.succ(), r) + yield z + + +def partition(z: MemoryArray, l: Literal, r: Literal): + p = mid_index(z, l, r, Literal((int(l)+int(r))//2)) + swap(z, p, r) + with MemoryCell(z[r]) as pivot, MemoryCell(l) as i, MemoryCell(r.pred()) as j: + while i < j: + while z[i] < pivot: + i.set(i.succ()) + while j > l and z[j] >= pivot: + j.set(j.pred()) + if i < j: + swap(z, int(i), int(j)) + i.set(i.succ()) + j.set(j.pred()) + if i == j and z[i] < pivot: + i.set(i.succ()) + if z[i] != pivot: + swap(z, int(i), int(r)) + return Literal(i) + +def mid_index(z: MemoryArray, i1, i2, i3): + if z[i1] < z[i2] < z[i3]: + return i2 + elif z[i3] < z[i2] < z[i1]: + return i2 + elif z[i2] < z[i1] < z[i3]: + return i1 + elif z[i3] < z[i1] < z[i2]: + return i1 + else: + return i3 + +def quick_sort(z: MemoryArray, l: Literal = None, r: Literal = None): + if l is None: + l = Literal(0) + if r is None: + r = z.length().pred() + sort_generator = quick_sort_stepwise(z, l, r) + while True: + try: + next(sort_generator) + except StopIteration: + break + + +def sort_file(filename, sort_func): + z = MemoryArray.create_array_from_file(filename) + sort_func(z) + return z + + +def analyze_complexity(sort_func, sizes, presorted=False): + """ + Analysiert die Komplexität einer Sortierfunktion. + + :param sort_func: Die Funktion, die analysiert wird. + :param sizes: Eine Liste von Eingabegrößen für die Analyse. + """ + for size in sizes: + MemoryManager.purge() # Speicher zurücksetzen + if presorted: + random_array = MemoryArray.create_sorted_array(size) + else: + random_array = MemoryArray.create_random_array(size, -100, 100) + sort_func(random_array) + MemoryManager.save_stats(size) + + MemoryManager.plot_stats(["cells", "compares", "writes"]) + + +def swap(z: MemoryArray, i: int, j: int): + tmp = z[Literal(i)].value + z[Literal(i)] = z[Literal(j)] + z[Literal(j)].set(tmp) + + +if __name__ == '__main__': + sizes = range(10, 101, 5) + analyze_complexity(quick_sort, sizes) + analyze_complexity(quick_sort, sizes, True) diff --git a/praktika/04_bin_baum/bin_tree_node.py b/praktika/04_bin_baum/bin_tree_node.py new file mode 100644 index 0000000..da79af1 --- /dev/null +++ b/praktika/04_bin_baum/bin_tree_node.py @@ -0,0 +1,15 @@ +from utils.memory_cell import MemoryCell + +class BinaryTreeNode(MemoryCell): + + def __init__(self, value): + super().__init__(value) + self.left = None + self.right = None + + def __repr__(self): + return f"BinaryTreeNode(value={self.value}, left={self.left}, right={self.right})" + + def __str__(self): + return str(self.value) + diff --git a/utils/memory_array.py b/utils/memory_array.py index 3d3b266..239f79d 100644 --- a/utils/memory_array.py +++ b/utils/memory_array.py @@ -102,6 +102,13 @@ class MemoryArray: a.reset_counters() return a + def __str__(self): + result = "[ " + for cell in self.cells: + result += str(cell) + ", " + result += "]" + return result + if __name__ == "__main__": import random diff --git a/vorlesung/03_fortgeschrittenes_sortieren/quick_sorting.py b/vorlesung/03_fortgeschrittenes_sortieren/quick_sorting.py index c34b990..9857f76 100644 --- a/vorlesung/03_fortgeschrittenes_sortieren/quick_sorting.py +++ b/vorlesung/03_fortgeschrittenes_sortieren/quick_sorting.py @@ -5,7 +5,6 @@ from utils.memory_range import mrange from utils.literal import Literal def quick_sort_stepwise(z: MemoryArray, l: Literal, r: Literal): - n = z.length() if l < r: q = partition(z, l, r) yield z @@ -77,6 +76,6 @@ def swap(z: MemoryArray, i: int, j: int): if __name__ == '__main__': - sizes = range(10, 101, 10) - analyze_complexity(quick_sort, sizes) - # analyze_complexity(quick_sort, sizes, True) + sizes = range(10, 101, 5) + #analyze_complexity(quick_sort, sizes) + analyze_complexity(quick_sort, sizes, True) diff --git a/vorlesung/04_besondere_sortierverfahren/count_sorting.py b/vorlesung/04_besondere_sortierverfahren/count_sorting.py new file mode 100644 index 0000000..507115d --- /dev/null +++ b/vorlesung/04_besondere_sortierverfahren/count_sorting.py @@ -0,0 +1,60 @@ +from utils.memory_array import MemoryArray +from utils.memory_cell import MemoryCell +from utils.memory_manager import MemoryManager +from utils.memory_range import mrange +from utils.literal import Literal + + + +def count_sort(a: MemoryArray, b: MemoryArray, k: int): + c = MemoryArray(Literal(k + 1)) + for i in mrange(Literal(k + 1)): + c[i].set(Literal(0)) + + for j in mrange(a.length()): + c[a[j]].set(c[a[j]].succ()) + + for i in mrange(Literal(1), Literal(k + 1)): + c[i].set(int(c[i]) + int(c[i.pred()])) + + for j in mrange(a.length().pred(), Literal(-1), Literal(-1)): + b[c[a[j]].pred()].set(a[j]) + c[a[j]].set(c[a[j]].pred()) + + + +def analyze_complexity(sizes, presorted=False): + """ + Analysiert die Komplexität einer Sortierfunktion. + + :param sizes: Eine Liste von Eingabegrößen für die Analyse. + """ + for size in sizes: + MemoryManager.purge() # Speicher zurücksetzen + if presorted: + random_array = MemoryArray.create_sorted_array(size, 0, 100) + else: + random_array = MemoryArray.create_random_array(size, 0, 100) + dest_array = MemoryArray(Literal(size)) + count_sort(random_array, dest_array, 100) + MemoryManager.save_stats(size) + + MemoryManager.plot_stats(["cells", "compares", "writes"]) + + +def swap(z: MemoryArray, i: int, j: int): + tmp = z[Literal(i)].value + z[Literal(i)] = z[Literal(j)] + z[Literal(j)].set(tmp) + + +if __name__ == '__main__': + + # Test the count_sort function + a = MemoryArray([2, 5, 3, 0, 2, 3, 0, 3]) + b = MemoryArray(Literal(len(a))) + count_sort(a, b, 5) + + sizes = range(10, 101, 10) + analyze_complexity(sizes) + # analyze_complexity(sizes, True) diff --git a/vorlesung/05_binaere_baeume/bin_search.py b/vorlesung/05_binaere_baeume/bin_search.py new file mode 100644 index 0000000..1bb0299 --- /dev/null +++ b/vorlesung/05_binaere_baeume/bin_search.py @@ -0,0 +1,61 @@ +import random + +from utils.memory_array import MemoryArray +from utils.memory_cell import MemoryCell +from utils.memory_manager import MemoryManager +from utils.memory_range import mrange +from utils.literal import Literal + + +def binary_search(z: MemoryArray, s: MemoryCell, l: Literal = None, r: Literal = None): + """ + Perform a binary search on the sorted array z for the value x. + """ + if l is None: + l = Literal(0) + if r is None: + r = Literal(z.length().pred()) + if l > r: + return None + with MemoryCell(l) as m: + m += r + m //= Literal(2) + if s < z[m]: + return binary_search(z, s, l, m.pred()) + elif s > z[m]: + return binary_search(z, s, m.succ(), r) + else: + return 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 + random_array = MemoryArray.create_sorted_array(size) + search_value = random.randint(-100, 100) + binary_search(random_array, MemoryCell(search_value)) + MemoryManager.save_stats(size) + + MemoryManager.plot_stats(["cells", "compares", "adds"]) + + + + +if __name__ == "__main__": + # Example usage + arr = MemoryArray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) + search_value = MemoryCell(8) + result = binary_search(arr, search_value) + if result is not None: + print(f"Value {search_value} found at index {result}.") + else: + print(f"Value {search_value} not found in the array.") + + + sizes = range(1, 1001, 2) + analyze_complexity(sizes)