Quick Sort and Heap Sort
This commit is contained in:
parent
32190dc104
commit
27a37037d1
@ -2,11 +2,24 @@ from utils.memory_manager import MemoryManager
|
||||
from utils.literal import Literal
|
||||
|
||||
class MemoryCell (Literal):
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
"""Erstellt eine neue Instanz von MemoryCell."""
|
||||
instance = MemoryManager().acquire_cell()
|
||||
if instance is None:
|
||||
instance = super().__new__(cls)
|
||||
MemoryManager().register_cell(instance)
|
||||
return instance
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
MemoryManager().release_cell(self)
|
||||
|
||||
def __init__(self, value=None):
|
||||
"""Initialisiert eine Speicherzelle mit optionalem Startwert."""
|
||||
super().__init__(value)
|
||||
manager = MemoryManager.get_instance()
|
||||
manager.add_cell(self)
|
||||
self.write_count = 0
|
||||
self.add_count = 0
|
||||
self.sub_count = 0
|
||||
@ -171,10 +184,6 @@ class MemoryCell (Literal):
|
||||
self.div(other)
|
||||
return self
|
||||
|
||||
def __imod__(self, other):
|
||||
self.mod(other)
|
||||
return self
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
a = MemoryCell(5)
|
||||
|
@ -1,63 +1,72 @@
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import queue
|
||||
|
||||
|
||||
class MemoryManager:
|
||||
|
||||
instance = None
|
||||
_instance = None
|
||||
stats = {}
|
||||
|
||||
@staticmethod
|
||||
def get_instance():
|
||||
if MemoryManager.instance is None:
|
||||
MemoryManager.instance = MemoryManager()
|
||||
return MemoryManager.instance
|
||||
def __new__(cls, *args, **kwargs):
|
||||
"""Erstellt eine einzige Instanz von MemoryManager."""
|
||||
if cls._instance is None:
|
||||
cls._instance = super().__new__(cls)
|
||||
cls._instance._initialize() # Eigene Init-Methode, damit __init__ nicht mehrfach läuft
|
||||
return cls._instance
|
||||
|
||||
def _initialize(self):
|
||||
"""Initialisiert die Speicherverwaltung (einmalig)."""
|
||||
self.cells = []
|
||||
self._pool = queue.Queue()
|
||||
self._finalizers = {}
|
||||
|
||||
|
||||
@staticmethod
|
||||
def count_cells():
|
||||
return len(MemoryManager.get_instance().cells)
|
||||
return len(MemoryManager().cells)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def count_reads():
|
||||
return sum([cell.read_count for cell in MemoryManager.get_instance().cells])
|
||||
return sum([cell.read_count for cell in MemoryManager().cells])
|
||||
|
||||
@staticmethod
|
||||
def count_writes():
|
||||
return sum([cell.write_count for cell in MemoryManager.get_instance().cells])
|
||||
return sum([cell.write_count for cell in MemoryManager().cells])
|
||||
|
||||
@staticmethod
|
||||
def count_compares():
|
||||
return sum([cell.compare_count for cell in MemoryManager.get_instance().cells])
|
||||
return sum([cell.compare_count for cell in MemoryManager().cells])
|
||||
|
||||
@staticmethod
|
||||
def count_adds():
|
||||
return sum([cell.add_count for cell in MemoryManager.get_instance().cells])
|
||||
return sum([cell.add_count for cell in MemoryManager().cells])
|
||||
|
||||
@staticmethod
|
||||
def count_subs():
|
||||
return sum([cell.sub_count for cell in MemoryManager.get_instance().cells])
|
||||
return sum([cell.sub_count for cell in MemoryManager().cells])
|
||||
|
||||
@staticmethod
|
||||
def count_muls():
|
||||
return sum([cell.mul_count for cell in MemoryManager.get_instance().cells])
|
||||
return sum([cell.mul_count for cell in MemoryManager().cells])
|
||||
|
||||
@staticmethod
|
||||
def count_divs():
|
||||
return sum([cell.div_count for cell in MemoryManager.get_instance().cells])
|
||||
return sum([cell.div_count for cell in MemoryManager().cells])
|
||||
|
||||
@staticmethod
|
||||
def count_bitops():
|
||||
return sum([cell.bitop_count for cell in MemoryManager.get_instance().cells])
|
||||
return sum([cell.bitop_count for cell in MemoryManager().cells])
|
||||
|
||||
@staticmethod
|
||||
def reset():
|
||||
manager = MemoryManager.get_instance()
|
||||
manager = MemoryManager()
|
||||
for cell in manager.cells:
|
||||
cell.reset_counters()
|
||||
|
||||
@staticmethod
|
||||
def purge():
|
||||
MemoryManager.instance = None
|
||||
MemoryManager._instance = None
|
||||
|
||||
@staticmethod
|
||||
def save_stats(count):
|
||||
@ -91,8 +100,49 @@ class MemoryManager:
|
||||
plt.xlabel("n")
|
||||
plt.show()
|
||||
|
||||
def __init__(self):
|
||||
self.cells = []
|
||||
|
||||
def add_cell(self, cell):
|
||||
def acquire_cell(self):
|
||||
try:
|
||||
return self._pool.get_nowait()
|
||||
except queue.Empty:
|
||||
return None
|
||||
|
||||
def register_cell(self, cell):
|
||||
self.cells.append(cell)
|
||||
|
||||
def release_cell(self, cell):
|
||||
self._pool.put(cell)
|
||||
|
||||
|
||||
class Testcell:
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
instance = MemoryManager().acquire_cell()
|
||||
if instance is None:
|
||||
instance = super().__new__(cls)
|
||||
MemoryManager().register_cell(instance)
|
||||
return instance
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
MemoryManager().release_cell(self)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
# Einfaches Anlegen einer Zelle
|
||||
a = Testcell()
|
||||
print(MemoryManager.count_cells())
|
||||
|
||||
# Anlegen einer Zelle und Beenden des Scopes
|
||||
with Testcell() as b:
|
||||
print(MemoryManager.count_cells())
|
||||
|
||||
print(MemoryManager.count_cells())
|
||||
|
||||
# Reuse einer Zelle
|
||||
c = Testcell()
|
||||
print(MemoryManager.count_cells())
|
||||
|
||||
|
@ -58,4 +58,4 @@ def swap(z: MemoryArray, i: int, j: int):
|
||||
|
||||
if __name__ == '__main__':
|
||||
analyze_complexity(insert_sort, [10, 20, 30, 40, 50, 60, 70, 80, 90, 100])
|
||||
analyze_complexity(insert_sort, [10, 20, 30, 40, 50, 60, 70, 80, 90, 100], True)
|
||||
#analyze_complexity(insert_sort, [10, 20, 30, 40, 50, 60, 70, 80, 90, 100], True)
|
||||
|
42
vorlesung/03_fortgeschrittenes_sortieren/heap_game.py
Normal file
42
vorlesung/03_fortgeschrittenes_sortieren/heap_game.py
Normal file
@ -0,0 +1,42 @@
|
||||
import random
|
||||
import pygame
|
||||
from utils.game import Game
|
||||
from utils.memory_array import MemoryArray
|
||||
from utils.literal import Literal
|
||||
from heap_sorting import heap_sort_stepwise
|
||||
|
||||
WHITE = (255, 255, 255)
|
||||
BLUE = (0, 0, 255)
|
||||
|
||||
class HeapGame(Game):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Heap Game", fps=20, size=(400, 400))
|
||||
random.seed()
|
||||
l =list(range(1, 101))
|
||||
random.shuffle(l)
|
||||
self.z = MemoryArray(l)
|
||||
self.finished = False
|
||||
self.sort_generator = heap_sort_stepwise(self.z)
|
||||
|
||||
def update_game(self):
|
||||
if not self.finished:
|
||||
try:
|
||||
next(self.sort_generator)
|
||||
except StopIteration:
|
||||
self.finished = True
|
||||
return True
|
||||
|
||||
def draw_game(self):
|
||||
self.screen.fill(WHITE)
|
||||
for i, cell in enumerate(self.z):
|
||||
x = 50 + i*3
|
||||
y = 350 - cell.value * 3
|
||||
pygame.draw.rect(self.screen, BLUE, (x, y, 3, 3))
|
||||
super().draw_game()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sort_game = HeapGame()
|
||||
sort_game.run()
|
||||
|
93
vorlesung/03_fortgeschrittenes_sortieren/heap_sorting.py
Normal file
93
vorlesung/03_fortgeschrittenes_sortieren/heap_sorting.py
Normal file
@ -0,0 +1,93 @@
|
||||
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 heap_sort_stepwise(z: MemoryArray):
|
||||
n = z.length()
|
||||
yield from make_max_heap(z)
|
||||
with MemoryCell(n) as heapsize:
|
||||
for i in mrange(n, 1, -1):
|
||||
swap(z, 0, i.pred())
|
||||
yield z
|
||||
heapsize.set(heapsize.pred())
|
||||
yield from max_heapyfy(z, Literal(1), heapsize)
|
||||
|
||||
|
||||
def heap_sort(z: MemoryArray):
|
||||
sort_generator = heap_sort_stepwise(z)
|
||||
while True:
|
||||
try:
|
||||
next(sort_generator)
|
||||
except StopIteration:
|
||||
break
|
||||
|
||||
|
||||
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 make_max_heap(z: MemoryArray):
|
||||
n = z.length()
|
||||
for i in mrange(int(n) // 2, 0, -1):
|
||||
yield from max_heapyfy(z, i, n)
|
||||
|
||||
|
||||
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)
|
||||
yield z
|
||||
yield from max_heapyfy(z, max_value, heapsize)
|
||||
|
||||
|
||||
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, 10)
|
||||
analyze_complexity(heap_sort, sizes)
|
||||
# analyze_complexity(quick_sort, sizes, True)
|
42
vorlesung/03_fortgeschrittenes_sortieren/quick_game.py
Normal file
42
vorlesung/03_fortgeschrittenes_sortieren/quick_game.py
Normal file
@ -0,0 +1,42 @@
|
||||
import random
|
||||
import pygame
|
||||
from utils.game import Game
|
||||
from utils.memory_array import MemoryArray
|
||||
from utils.literal import Literal
|
||||
from quick_sorting import quick_sort_stepwise
|
||||
|
||||
WHITE = (255, 255, 255)
|
||||
BLUE = (0, 0, 255)
|
||||
|
||||
class QuickGame(Game):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Quick Game", fps=10, size=(400, 400))
|
||||
random.seed()
|
||||
l =list(range(1, 101))
|
||||
random.shuffle(l)
|
||||
self.z = MemoryArray(l)
|
||||
self.finished = False
|
||||
self.sort_generator = quick_sort_stepwise(self.z, Literal(0), Literal(self.z.length().pred()))
|
||||
|
||||
def update_game(self):
|
||||
if not self.finished:
|
||||
try:
|
||||
next(self.sort_generator)
|
||||
except StopIteration:
|
||||
self.finished = True
|
||||
return True
|
||||
|
||||
def draw_game(self):
|
||||
self.screen.fill(WHITE)
|
||||
for i, cell in enumerate(self.z):
|
||||
x = 50 + i*3
|
||||
y = 350 - cell.value * 3
|
||||
pygame.draw.rect(self.screen, BLUE, (x, y, 3, 3))
|
||||
super().draw_game()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sort_game = QuickGame()
|
||||
sort_game.run()
|
||||
|
82
vorlesung/03_fortgeschrittenes_sortieren/quick_sorting.py
Normal file
82
vorlesung/03_fortgeschrittenes_sortieren/quick_sorting.py
Normal file
@ -0,0 +1,82 @@
|
||||
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 quick_sort_stepwise(z: MemoryArray, l: Literal, r: Literal):
|
||||
n = z.length()
|
||||
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):
|
||||
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 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, 10)
|
||||
analyze_complexity(quick_sort, sizes)
|
||||
# analyze_complexity(quick_sort, sizes, True)
|
Loading…
x
Reference in New Issue
Block a user