forked from hofmannol/AlgoDatSoSe25
Compare commits
No commits in common. "02d9557e27679bc9492d947f11f0e5a3a8aaa006" and "141ff08b8215f35f26eccb77f25417d071f93410" have entirely different histories.
02d9557e27
...
141ff08b82
@ -1,246 +0,0 @@
|
|||||||
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