forked from hofmannol/AlgoDatSoSe25
Compare commits
3 Commits
141ff08b82
...
02d9557e27
Author | SHA1 | Date | |
---|---|---|---|
02d9557e27 | |||
58f66fc1ff | |||
552f226e76 |
246
schoeffelbe/pr05.py
Normal file
246
schoeffelbe/pr05.py
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
import logging
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
# logging.basicConfig(level=logging.DEBUG)
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
def timeMS(func, *args, **kwargs):
|
||||||
|
startTime = time.perf_counter()
|
||||||
|
result = func(*args, **kwargs)
|
||||||
|
endTime = time.perf_counter()
|
||||||
|
elapsedMS = (endTime - startTime) * 1000 # Convert to milliseconds
|
||||||
|
print(f"{func.__name__} took {elapsedMS:.2f} ms")
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
from utils.memory_array import MemoryArray
|
||||||
|
from utils.literal import Literal
|
||||||
|
from utils.memory_manager import MemoryManager
|
||||||
|
from vorlesung.L05_binaere_baeume.bin_tree import BinaryTree
|
||||||
|
from vorlesung.L05_binaere_baeume.bin_tree_node import BinaryTreeNode
|
||||||
|
|
||||||
|
def analyze_complexity(fn, sizes):
|
||||||
|
"""
|
||||||
|
Analysiert die Komplexität einer maximalen Teilfolgenfunktion.
|
||||||
|
|
||||||
|
:param max_sequence_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
|
||||||
|
random_array = MemoryArray.create_random_array(size, -100, 100)
|
||||||
|
fn(random_array, Literal(0), random_array.length().pred())
|
||||||
|
MemoryManager.save_stats(size)
|
||||||
|
|
||||||
|
MemoryManager.plot_stats(["cells", "adds", "compares", "reads", "writes"])
|
||||||
|
|
||||||
|
lineAccumulator = []
|
||||||
|
|
||||||
|
# Returnvalue does not get forwarded so we can not work with return.
|
||||||
|
# Will try glob vars to append the string
|
||||||
|
# Signature: def print_node(node, indent=0, line=None):
|
||||||
|
def clbk_graphvizify(toDecorate : BinaryTreeNode, indent=0, line=None):
|
||||||
|
global lineAccumulator
|
||||||
|
|
||||||
|
if isinstance(toDecorate, AVLTreeNode):
|
||||||
|
lineAccumulator.append(f'n_{id(toDecorate)} [label=<{toDecorate.value}<BR/><FONT COLOR="RED" POINT-SIZE="10.0" FACE="ambrosia">B: {toDecorate.balanceFactor}</FONT>>]')
|
||||||
|
else:
|
||||||
|
lineAccumulator.append(f"n_{id(toDecorate)} [label={toDecorate.value}]")
|
||||||
|
|
||||||
|
# Create edges for nodes with Child (use l - r)
|
||||||
|
if toDecorate.left is not None:
|
||||||
|
lineAccumulator.append(f"n_{id(toDecorate)} -> n_{id(toDecorate.left)}")
|
||||||
|
|
||||||
|
if toDecorate.right is not None:
|
||||||
|
lineAccumulator.append(f"n_{id(toDecorate)} -> n_{id(toDecorate.right)}")
|
||||||
|
|
||||||
|
|
||||||
|
def graphvizify() -> str:
|
||||||
|
# Header
|
||||||
|
result = "digraph {\n\t"
|
||||||
|
# Body
|
||||||
|
result += ('\n\t'.join(str(item) for item in lineAccumulator))
|
||||||
|
# Footer
|
||||||
|
result += "\n}"
|
||||||
|
return result
|
||||||
|
|
||||||
|
class AVLTreeNode(BinaryTreeNode):
|
||||||
|
def __init__(self, value):
|
||||||
|
super().__init__(value)
|
||||||
|
self.parentRef = None
|
||||||
|
# Start balanced as we probably have no children right after insert
|
||||||
|
self.balanceFactor = Literal(0)
|
||||||
|
|
||||||
|
def rightRotate(self, node) -> 'AVLTreeNode|None':
|
||||||
|
if node is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
oLeft = node.left;
|
||||||
|
oLeft.parentRef = node.parentRef;
|
||||||
|
node.left = oLeft.right;
|
||||||
|
|
||||||
|
if node.left is not None:
|
||||||
|
node.left.parentRef = node;
|
||||||
|
|
||||||
|
oLeft.right = node;
|
||||||
|
node.parentRef = oLeft;
|
||||||
|
|
||||||
|
if oLeft.parentRef is not None:
|
||||||
|
if oLeft.parentRef.right is node:
|
||||||
|
oLeft.parentRef.right = oLeft;
|
||||||
|
elif oLeft.parentRef.left is node:
|
||||||
|
oLeft.parentRef.left = oLeft;
|
||||||
|
|
||||||
|
node.getSetBalanceFactor()
|
||||||
|
oLeft.getSetBalanceFactor()
|
||||||
|
|
||||||
|
return oLeft
|
||||||
|
|
||||||
|
def leftRotate(self, node) -> 'AVLTreeNode|None':
|
||||||
|
if node is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
oRight = node.right
|
||||||
|
oRight.parentRef = node.parentRef
|
||||||
|
node.right = oRight.left
|
||||||
|
|
||||||
|
if node.right is not None:
|
||||||
|
node.right.parentRef = node
|
||||||
|
|
||||||
|
oRight.left = node
|
||||||
|
node.parentRef = oRight
|
||||||
|
|
||||||
|
if oRight.parentRef is not None:
|
||||||
|
if oRight.parentRef.right is node:
|
||||||
|
oRight.parentRef.right = oRight
|
||||||
|
elif oRight.parentRef.left is node:
|
||||||
|
oRight.parentRef.left = oRight
|
||||||
|
|
||||||
|
node.getSetBalanceFactor()
|
||||||
|
oRight.getSetBalanceFactor()
|
||||||
|
|
||||||
|
return oRight
|
||||||
|
|
||||||
|
def getSetBalanceFactor(self) -> Literal:
|
||||||
|
leftHeight = self.left.height() if self.left else 0
|
||||||
|
rightHeight = self.right.height() if self.right else 0
|
||||||
|
self.balanceFactor = Literal(rightHeight - leftHeight)
|
||||||
|
return self.balanceFactor
|
||||||
|
|
||||||
|
def rightLeftRotate(self, node) -> 'AVLTreeNode|None':
|
||||||
|
node.right = self.rightRotate(node.right)
|
||||||
|
return self.leftRotate(node)
|
||||||
|
|
||||||
|
def leftRightRotate(self, node) -> 'AVLTreeNode|None':
|
||||||
|
node.left = self.leftRotate(node.left)
|
||||||
|
return self.rightRotate(node)
|
||||||
|
|
||||||
|
|
||||||
|
def debugTraverse(node, source=1):
|
||||||
|
if node is None:
|
||||||
|
return None
|
||||||
|
logger.debug(f"{node.value} {node.getSetBalanceFactor()} {source}")
|
||||||
|
debugTraverse(node.left, 10);
|
||||||
|
debugTraverse(node.right, 20);
|
||||||
|
|
||||||
|
|
||||||
|
class AVLTree(BinaryTree):
|
||||||
|
# @override
|
||||||
|
def new_node(self, value) -> AVLTreeNode:
|
||||||
|
return AVLTreeNode(value)
|
||||||
|
|
||||||
|
def balanceAVLTree(self, node : AVLTreeNode):
|
||||||
|
# balance < -1 means imbalance to the left, > 1 means imbalance to the right
|
||||||
|
logger.debug("in")
|
||||||
|
if node is None:
|
||||||
|
return None
|
||||||
|
logger.debug("out")
|
||||||
|
|
||||||
|
node.getSetBalanceFactor()
|
||||||
|
logger.debug(f"Parent Balancing for {node.value} -> {node.balanceFactor} {node.left.height() if node.left else None} and {node.right.height() if node.right else None}")
|
||||||
|
|
||||||
|
# imbalance to left -> If we enter this we cannot LOGICALLY have a left=None node -> No need to chekc
|
||||||
|
if node.balanceFactor < Literal(-1):
|
||||||
|
# Left-Left
|
||||||
|
if node.left.balanceFactor <= Literal(0): # type: ignore -> Ignoring pywright error, see comment above
|
||||||
|
# Wow, this syntax is sketchy ^^
|
||||||
|
# TODO Maybe declare as static if python supports this? Or just leaf param be?
|
||||||
|
logger.debug("rr")
|
||||||
|
node = node.rightRotate(node)
|
||||||
|
# Left-Right
|
||||||
|
else:
|
||||||
|
# TODO Maybe declare as static if python supports this? Or just leaf param be?
|
||||||
|
logger.debug("lrr")
|
||||||
|
node = node.leftRightRotate(node)
|
||||||
|
|
||||||
|
# Right heavy
|
||||||
|
# imbalance to right -> If we enter this we cannot LOGICALLY have a right=None node -> No need to chekc
|
||||||
|
if node.balanceFactor > Literal(1):
|
||||||
|
# Right-Right case
|
||||||
|
if node.right.balanceFactor >= Literal(0): # type: ignore -> Ignoring pywright error, see comment above
|
||||||
|
# TODO Maybe declare as static if python supports this? Or just leaf param be?
|
||||||
|
logger.debug("lr")
|
||||||
|
node = node.leftRotate(node)
|
||||||
|
# Right-Left case
|
||||||
|
else:
|
||||||
|
# TODO Maybe declare as static if python supports this? Or just leaf param be?
|
||||||
|
logger.debug("rlr")
|
||||||
|
node = node.rightLeftRotate(node)
|
||||||
|
|
||||||
|
logger.debug(f"Reached {node.parentRef}")
|
||||||
|
if node.parentRef is not None:
|
||||||
|
logger.debug(f"Calling again for {node.parentRef.value}");
|
||||||
|
self.balanceAVLTree(node.parentRef);
|
||||||
|
else:
|
||||||
|
self.root = node;
|
||||||
|
|
||||||
|
# Node is balanced
|
||||||
|
return node
|
||||||
|
|
||||||
|
# @override
|
||||||
|
def insert(self, value):
|
||||||
|
node, parent = super().insert(value)
|
||||||
|
# NOTE Python does not have a Problem with NOT tellin us that we override something important
|
||||||
|
# or something that does not exist.... This Makes for AWESOME debugging .... ... ...
|
||||||
|
node.parentRef = parent
|
||||||
|
|
||||||
|
if parent:
|
||||||
|
node = self.balanceAVLTree(node.parentRef)
|
||||||
|
|
||||||
|
return node, parent
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
tree = AVLTree()
|
||||||
|
|
||||||
|
### Force RR
|
||||||
|
# testData = [30, 20, 10];
|
||||||
|
# for value in testData:
|
||||||
|
# tree.insert(MemoryCell(value));
|
||||||
|
|
||||||
|
### Force LR
|
||||||
|
# testData = [10, 20, 30];
|
||||||
|
# for value in testData:
|
||||||
|
# tree.insert(MemoryCell(value));
|
||||||
|
|
||||||
|
### Force LRR
|
||||||
|
# testData = [30, 10, 20]
|
||||||
|
# for value in testData:
|
||||||
|
# tree.insert(MemoryCell(value))
|
||||||
|
|
||||||
|
### Force RLR
|
||||||
|
# testData = [10, 30, 20]
|
||||||
|
# for value in testData:
|
||||||
|
# tree.insert(MemoryCell(value))
|
||||||
|
|
||||||
|
# Force rebuild of our balanceFactor indices...
|
||||||
|
# debugTraverse(tree.root)
|
||||||
|
|
||||||
|
binTreeData = MemoryArray.create_array_from_file("data/seq0.txt")
|
||||||
|
for value in binTreeData:
|
||||||
|
tree.insert(value)
|
||||||
|
|
||||||
|
|
||||||
|
lineAccumulator.clear();
|
||||||
|
tree.in_order_traversal(clbk_graphvizify)
|
||||||
|
# tree.tree_structure_traversal(clbk_graphvizify)
|
||||||
|
print(graphvizify())
|
Loading…
x
Reference in New Issue
Block a user