forked from hofmannol/AlgoDatSoSe25
Implemented AVL Insert, sort and some debugstuff to find weird pythonissues
This commit is contained in:
parent
552f226e76
commit
58f66fc1ff
@ -14,11 +14,8 @@ def timeMS(func, *args, **kwargs):
|
|||||||
|
|
||||||
|
|
||||||
from utils.memory_array import MemoryArray
|
from utils.memory_array import MemoryArray
|
||||||
from utils.memory_cell import MemoryCell
|
|
||||||
from utils.literal import Literal
|
from utils.literal import Literal
|
||||||
from utils.constants import MAX_VALUE
|
|
||||||
from utils.memory_manager import MemoryManager
|
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 import BinaryTree
|
||||||
from vorlesung.L05_binaere_baeume.bin_tree_node import BinaryTreeNode
|
from vorlesung.L05_binaere_baeume.bin_tree_node import BinaryTreeNode
|
||||||
|
|
||||||
@ -39,12 +36,16 @@ def analyze_complexity(fn, sizes):
|
|||||||
|
|
||||||
lineAccumulator = []
|
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):
|
# Signature: def print_node(node, indent=0, line=None):
|
||||||
def clbk_graphvizify(toDecorate : BinaryTreeNode, indent=0, line=None):
|
def clbk_graphvizify(toDecorate : BinaryTreeNode, indent=0, line=None):
|
||||||
global lineAccumulator
|
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)
|
# Create edges for nodes with Child (use l - r)
|
||||||
if toDecorate.left is not None:
|
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:
|
if toDecorate.right is not None:
|
||||||
lineAccumulator.append(f"n_{id(toDecorate)} -> n_{id(toDecorate.right)}")
|
lineAccumulator.append(f"n_{id(toDecorate)} -> n_{id(toDecorate.right)}")
|
||||||
|
|
||||||
|
|
||||||
def graphvizify() -> str:
|
def graphvizify() -> str:
|
||||||
# Header
|
# Header
|
||||||
result = "digraph {\n\t"
|
result = "digraph {\n\t"
|
||||||
# Body
|
# Body
|
||||||
result += ('\n\t'.join(str(item) for item in lineAccumulator))
|
result += ('\n\t'.join(str(item) for item in lineAccumulator))
|
||||||
# Foot
|
# Footer
|
||||||
result += "\n}"
|
result += "\n}"
|
||||||
return result
|
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__':
|
if __name__ == '__main__':
|
||||||
tree = BinaryTree()
|
tree = AVLTree()
|
||||||
values = [5, 3, 7, 2, 4, 6, 5, 8]
|
|
||||||
|
### 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")
|
binTreeData = MemoryArray.create_array_from_file("data/seq0.txt")
|
||||||
for value in binTreeData:
|
for value in binTreeData:
|
||||||
tree.insert(value)
|
tree.insert(value)
|
||||||
|
|
||||||
# for value in values:
|
|
||||||
# tree.insert(value)
|
|
||||||
|
|
||||||
|
lineAccumulator.clear();
|
||||||
tree.in_order_traversal(clbk_graphvizify)
|
tree.in_order_traversal(clbk_graphvizify)
|
||||||
|
# tree.tree_structure_traversal(clbk_graphvizify)
|
||||||
print(graphvizify())
|
print(graphvizify())
|
||||||
|
Loading…
x
Reference in New Issue
Block a user