Implemented AVL Insert, sort and some debugstuff to find weird pythonissues

This commit is contained in:
Bernhard Schoeffel 2025-04-26 18:54:00 +02:00
parent 552f226e76
commit 58f66fc1ff

View File

@ -14,11 +14,8 @@ def timeMS(func, *args, **kwargs):
from utils.memory_array import MemoryArray
from utils.memory_cell import MemoryCell
from utils.literal import Literal
from utils.constants import MAX_VALUE
from utils.memory_manager import MemoryManager
from utils.memory_range import mrange
from vorlesung.L05_binaere_baeume.bin_tree import BinaryTree
from vorlesung.L05_binaere_baeume.bin_tree_node import BinaryTreeNode
@ -39,12 +36,16 @@ def analyze_complexity(fn, sizes):
lineAccumulator = []
# its not getting forwarded so we can not work with return. I will try glob vars to append the string
# 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
lineAccumulator.append(f"n_{id(toDecorate)} [label={toDecorate.value}]")
if isinstance(toDecorate, AVLTreeNode):
lineAccumulator.append(f"n_{id(toDecorate)} [label=\"{toDecorate.value}\\n{toDecorate.balanceFactor}\"]")
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:
@ -53,26 +54,193 @@ def clbk_graphvizify(toDecorate : BinaryTreeNode, indent=0, line=None):
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))
# Foot
# 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 = BinaryTree()
values = [5, 3, 7, 2, 4, 6, 5, 8]
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)
# for value in values:
# tree.insert(value)
lineAccumulator.clear();
tree.in_order_traversal(clbk_graphvizify)
# tree.tree_structure_traversal(clbk_graphvizify)
print(graphvizify())