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)