From 27d86de2906938345c41339b1083bc0ae1900a8e Mon Sep 17 00:00:00 2001 From: Oliver Hofmann Date: Fri, 11 Apr 2025 08:51:52 +0200 Subject: [PATCH 1/2] Praktikum 3 --- praktika/03_quick_and_heap/priority_queue.py | 131 ++++++++++++++++++ .../quick_sorting_enhanced.py | 93 +++++++++++++ utils/memory_array.py | 7 + .../quick_sorting.py | 7 +- 4 files changed, 234 insertions(+), 4 deletions(-) create mode 100644 praktika/03_quick_and_heap/priority_queue.py create mode 100644 praktika/03_quick_and_heap/quick_sorting_enhanced.py 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..8a6854f --- /dev/null +++ b/praktika/03_quick_and_heap/priority_queue.py @@ -0,0 +1,131 @@ +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"]) + + + +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) + 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/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) From 081353c6c0ccbcef58546407924f08a89e88fcaf Mon Sep 17 00:00:00 2001 From: Oliver Hofmann Date: Fri, 11 Apr 2025 08:58:07 +0200 Subject: [PATCH 2/2] Praktikum 3 --- praktika/03_quick_and_heap/priority_queue.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/praktika/03_quick_and_heap/priority_queue.py b/praktika/03_quick_and_heap/priority_queue.py index 8a6854f..0dc6161 100644 --- a/praktika/03_quick_and_heap/priority_queue.py +++ b/praktika/03_quick_and_heap/priority_queue.py @@ -107,6 +107,24 @@ def analyze_complexity_insert(sizes, presorted=False): 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) @@ -128,4 +146,5 @@ if __name__ == '__main__': sizes = range(10, 501, 5) analyze_complexity_insert(sizes, presorted=True) + analyze_complexity_pop(sizes, presorted=True)