lecture 5
This commit is contained in:
parent
8ab7c0a835
commit
5bb8b62fa9
@ -54,8 +54,8 @@ def median_pivot(z: AlgoDatArray, left: int, right: int) -> int:
|
|||||||
|
|
||||||
def quick_sort(z: AlgoDatArray, left: int, right: int):
|
def quick_sort(z: AlgoDatArray, left: int, right: int):
|
||||||
if left < right:
|
if left < right:
|
||||||
q = partition(z, left, right)
|
#q = partition(z, left, right)
|
||||||
#q = median_pivot(z, left, right)
|
q = median_pivot(z, left, right)
|
||||||
quick_sort(z, left, q-1)
|
quick_sort(z, left, q-1)
|
||||||
quick_sort(z, q+1, right)
|
quick_sort(z, q+1, right)
|
||||||
|
|
||||||
|
111
SoSe24/lec04_trees/avl_tree.py
Normal file
111
SoSe24/lec04_trees/avl_tree.py
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
from SoSe24.algodat.foundation import AlgoDatArray, AlgoDatValue, read_int_sequence
|
||||||
|
from SoSe24.lec04_trees.bin_tree import BinTree, BinTreeNode
|
||||||
|
from time import perf_counter as pfc
|
||||||
|
|
||||||
|
class AVLTreeNode(BinTreeNode):
|
||||||
|
def __init__(self, value: AlgoDatValue):
|
||||||
|
super().__init__(value)
|
||||||
|
self.parent = None
|
||||||
|
self.balance = 0
|
||||||
|
|
||||||
|
def update_balance(self):
|
||||||
|
left_height = self.left.height() if self.left else 0
|
||||||
|
right_height = self.right.height() if self.right else 0
|
||||||
|
self.balance = right_height - left_height
|
||||||
|
|
||||||
|
def right_rotate(self) -> BinTreeNode:
|
||||||
|
new_root = self.left
|
||||||
|
new_root.parent = self.parent
|
||||||
|
self.left = new_root.right
|
||||||
|
if self.left:
|
||||||
|
self.left.parent = self
|
||||||
|
new_root.right = self
|
||||||
|
self.parent = new_root
|
||||||
|
if new_root.parent:
|
||||||
|
if new_root.parent.left == self:
|
||||||
|
new_root.parent.left = new_root
|
||||||
|
else:
|
||||||
|
new_root.parent.right = new_root
|
||||||
|
self.update_balance()
|
||||||
|
new_root.update_balance()
|
||||||
|
return new_root
|
||||||
|
|
||||||
|
def left_rotate(self) -> BinTreeNode:
|
||||||
|
new_root = self.right
|
||||||
|
new_root.parent = self.parent
|
||||||
|
self.right = new_root.left
|
||||||
|
if self.right:
|
||||||
|
self.right.parent = self
|
||||||
|
new_root.left = self
|
||||||
|
self.parent = new_root
|
||||||
|
if new_root.parent:
|
||||||
|
if new_root.parent.left == self:
|
||||||
|
new_root.parent.left = new_root
|
||||||
|
else:
|
||||||
|
new_root.parent.right = new_root
|
||||||
|
self.update_balance()
|
||||||
|
new_root.update_balance()
|
||||||
|
return new_root
|
||||||
|
|
||||||
|
def right_left_rotate(self) -> BinTreeNode:
|
||||||
|
self.right = self.right.right_rotate()
|
||||||
|
return self.left_rotate()
|
||||||
|
|
||||||
|
def left_right_rotate(self) -> BinTreeNode:
|
||||||
|
self.left = self.left.left_rotate()
|
||||||
|
return self.right_rotate()
|
||||||
|
|
||||||
|
class AVLTree(BinTree):
|
||||||
|
|
||||||
|
def new_node(self, value: AlgoDatValue):
|
||||||
|
return AVLTreeNode(value)
|
||||||
|
|
||||||
|
def balance(self, node: AVLTreeNode):
|
||||||
|
node.update_balance()
|
||||||
|
if node.balance == -2:
|
||||||
|
if node.left.balance <= 0:
|
||||||
|
node = node.right_rotate()
|
||||||
|
else:
|
||||||
|
node = node.left_right_rotate()
|
||||||
|
elif node.balance == 2:
|
||||||
|
if node.right.balance >= 0:
|
||||||
|
node = node.left_rotate()
|
||||||
|
else:
|
||||||
|
node = node.right_left_rotate()
|
||||||
|
if node.parent:
|
||||||
|
self.balance(node.parent)
|
||||||
|
else:
|
||||||
|
self.root = node
|
||||||
|
|
||||||
|
def insert(self, value: AlgoDatValue):
|
||||||
|
node, parent = super().insert(value)
|
||||||
|
node.parent = parent
|
||||||
|
if parent:
|
||||||
|
self.balance(parent)
|
||||||
|
return node, parent
|
||||||
|
|
||||||
|
def delete(self, value: AlgoDatValue):
|
||||||
|
node, parent = super().delete(value)
|
||||||
|
if node:
|
||||||
|
node.parent = parent
|
||||||
|
if parent:
|
||||||
|
self.balance(parent)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
z = read_int_sequence("../../seq0.txt")
|
||||||
|
print(z, len(z))
|
||||||
|
start = pfc()
|
||||||
|
tree = AVLTree()
|
||||||
|
for i in z:
|
||||||
|
tree.insert(i)
|
||||||
|
tree.walk()
|
||||||
|
tree.tree_walk()
|
||||||
|
tree.levelwalk()
|
||||||
|
#tree.graph_walk()
|
||||||
|
tree.delete(AlgoDatValue(46))
|
||||||
|
tree.delete(AlgoDatValue(48))
|
||||||
|
tree.graph_walk()
|
||||||
|
print(f"Dauer: {pfc() - start:.4f}s")
|
||||||
|
AlgoDatValue.summary()
|
29
SoSe24/lec04_trees/avl_tree_plot.py
Normal file
29
SoSe24/lec04_trees/avl_tree_plot.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
from SoSe24.algodat.foundation import AlgoDatArray, AlgoDatValue, read_int_sequence, read_int_sequence_limited
|
||||||
|
import matplotlib
|
||||||
|
matplotlib.use('TkAgg')
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import avl_tree as avl
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
filename = "../../seq3_sorted.txt"
|
||||||
|
#filename = "../../seq3.txt"
|
||||||
|
dummy = read_int_sequence(filename)
|
||||||
|
n = len(dummy)
|
||||||
|
step = n // 100
|
||||||
|
|
||||||
|
memory_values = []
|
||||||
|
compare_values = []
|
||||||
|
|
||||||
|
for right_end in range(1, n, step):
|
||||||
|
AlgoDatValue.reset()
|
||||||
|
z = read_int_sequence_limited(filename, right_end)
|
||||||
|
tree = avl.AVLTree()
|
||||||
|
for i in z:
|
||||||
|
tree.insert(i)
|
||||||
|
memory_values.append(AlgoDatValue.memory)
|
||||||
|
compare_values.append(AlgoDatValue.compare)
|
||||||
|
|
||||||
|
plt.plot(range(1, n, step), memory_values, 'b', label='Memory')
|
||||||
|
plt.plot(range(1, n, step), compare_values, 'r', label='Compare')
|
||||||
|
plt.legend()
|
||||||
|
plt.show()
|
171
SoSe24/lec04_trees/bin_tree.py
Normal file
171
SoSe24/lec04_trees/bin_tree.py
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
from SoSe24.algodat.foundation import AlgoDatArray, AlgoDatValue, read_int_sequence
|
||||||
|
from time import perf_counter as pfc
|
||||||
|
|
||||||
|
class BinTreeNode:
|
||||||
|
def __init__(self, value: AlgoDatValue):
|
||||||
|
self.value = value
|
||||||
|
self.left = None
|
||||||
|
self.right = None
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.value}"
|
||||||
|
|
||||||
|
def height(self) -> int:
|
||||||
|
left_height = self.left.height() if self.left else 0
|
||||||
|
right_height = self.right.height() if self.right else 0
|
||||||
|
return 1 + max(left_height, right_height)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class BinTree:
|
||||||
|
def __init__(self):
|
||||||
|
self.root = None
|
||||||
|
|
||||||
|
def new_node(self, value: AlgoDatValue) -> BinTreeNode:
|
||||||
|
return BinTreeNode(value)
|
||||||
|
|
||||||
|
def insert(self, value: AlgoDatValue) -> (BinTreeNode, BinTreeNode):
|
||||||
|
if not self.root:
|
||||||
|
self.root = self.new_node(value)
|
||||||
|
return self.root, None
|
||||||
|
|
||||||
|
current = self.root
|
||||||
|
while True:
|
||||||
|
if value < current.value:
|
||||||
|
if current.left:
|
||||||
|
current = current.left
|
||||||
|
else:
|
||||||
|
current.left = self.new_node(value)
|
||||||
|
return current.left, current
|
||||||
|
elif value >= current.value:
|
||||||
|
if current.right:
|
||||||
|
current = current.right
|
||||||
|
else:
|
||||||
|
current.right = self.new_node(value)
|
||||||
|
return current.right, current
|
||||||
|
else:
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
def search(self, value: AlgoDatValue) -> BinTreeNode:
|
||||||
|
current = self.root
|
||||||
|
while current:
|
||||||
|
if value < current.value:
|
||||||
|
current = current.left
|
||||||
|
elif value > current.value:
|
||||||
|
current = current.right
|
||||||
|
else:
|
||||||
|
return current
|
||||||
|
return None
|
||||||
|
|
||||||
|
def delete(self, value: AlgoDatValue):
|
||||||
|
parent = None
|
||||||
|
current = self.root
|
||||||
|
while current:
|
||||||
|
if value < current.value:
|
||||||
|
parent = current
|
||||||
|
current = current.left
|
||||||
|
elif value > current.value:
|
||||||
|
parent = current
|
||||||
|
current = current.right
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
if current.left and current.right:
|
||||||
|
parent = current
|
||||||
|
successor = current.right
|
||||||
|
while successor.left:
|
||||||
|
parent = successor
|
||||||
|
successor = successor.left
|
||||||
|
current.value.value = successor.value.value
|
||||||
|
current = successor
|
||||||
|
|
||||||
|
if current.left:
|
||||||
|
child = current.left
|
||||||
|
else:
|
||||||
|
child = current.right
|
||||||
|
|
||||||
|
if not parent:
|
||||||
|
self.root = child
|
||||||
|
return child, None
|
||||||
|
elif parent.left == current:
|
||||||
|
parent.left = child
|
||||||
|
return child, parent
|
||||||
|
else:
|
||||||
|
parent.right = child
|
||||||
|
return child, parent
|
||||||
|
|
||||||
|
def walk(self): # in-order
|
||||||
|
print("[ ", end="")
|
||||||
|
self.walk_recursive(self.root, 0, 0)
|
||||||
|
print(" ]")
|
||||||
|
|
||||||
|
|
||||||
|
def graph_walk(self):
|
||||||
|
self.leaf_counter = 0
|
||||||
|
with open("../../graph.gv", "w") as file:
|
||||||
|
file.write("digraph BST {\n")
|
||||||
|
file.write(" node [fontname=\"Arial\"];\n")
|
||||||
|
self.graph_walk_recursive(self.root, file)
|
||||||
|
file.write("}")
|
||||||
|
|
||||||
|
def graph_walk_recursive(self, current, file):
|
||||||
|
if current is not None:
|
||||||
|
if current.left:
|
||||||
|
file.write(f"{current.value} -> {current.left.value}; \n")
|
||||||
|
self.graph_walk_recursive(current.left, file)
|
||||||
|
else:
|
||||||
|
file.write(f"left{self.leaf_counter} [shape=point]; \n")
|
||||||
|
file.write(f"{current.value} -> left{self.leaf_counter}; \n")
|
||||||
|
self.leaf_counter += 1
|
||||||
|
if current.right:
|
||||||
|
file.write(f"{current.value} -> {current.right.value}; \n")
|
||||||
|
self.graph_walk_recursive(current.right, file)
|
||||||
|
else:
|
||||||
|
file.write(f"right{self.leaf_counter} [shape=point]; \n")
|
||||||
|
file.write(f"{current.value} -> right{self.leaf_counter}; \n")
|
||||||
|
self.leaf_counter += 1
|
||||||
|
|
||||||
|
|
||||||
|
def tree_walk(self):
|
||||||
|
self.walk_recursive(self.root, 0, 1)
|
||||||
|
|
||||||
|
def walk_recursive(self, node: BinTreeNode, level = 0, increase = 1):
|
||||||
|
if node:
|
||||||
|
if increase >= 1:
|
||||||
|
end = "\n"
|
||||||
|
else:
|
||||||
|
end = " "
|
||||||
|
self.walk_recursive(node.left, level+increase, increase)
|
||||||
|
print(" "*level*3 + str(node.value), end=end)
|
||||||
|
self.walk_recursive(node.right, level+increase, increase)
|
||||||
|
|
||||||
|
def levelwalk(self):
|
||||||
|
if self.root is None:
|
||||||
|
return
|
||||||
|
queue = [self.root]
|
||||||
|
while queue:
|
||||||
|
current = queue.pop(0)
|
||||||
|
print(current.value, end=" ")
|
||||||
|
if current.left:
|
||||||
|
queue.append(current.left)
|
||||||
|
if current.right:
|
||||||
|
queue.append(current.right)
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
z = read_int_sequence("../../seq0.txt")
|
||||||
|
print(z, len(z))
|
||||||
|
start = pfc()
|
||||||
|
tree = BinTree()
|
||||||
|
for i in z:
|
||||||
|
tree.insert(i)
|
||||||
|
tree.walk()
|
||||||
|
tree.tree_walk()
|
||||||
|
tree.levelwalk()
|
||||||
|
tree.delete(AlgoDatValue(46))
|
||||||
|
tree.graph_walk()
|
||||||
|
print(f"Dauer: {pfc() - start:.4f}s")
|
||||||
|
AlgoDatValue.summary()
|
29
SoSe24/lec04_trees/bin_tree_plot.py
Normal file
29
SoSe24/lec04_trees/bin_tree_plot.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
from SoSe24.algodat.foundation import AlgoDatArray, AlgoDatValue, read_int_sequence, read_int_sequence_limited
|
||||||
|
import matplotlib
|
||||||
|
matplotlib.use('TkAgg')
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import bin_tree as bt
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
filename = "../../seq3_sorted.txt"
|
||||||
|
#filename = "../../seq3.txt"
|
||||||
|
dummy = read_int_sequence(filename)
|
||||||
|
n = len(dummy)
|
||||||
|
step = n // 100
|
||||||
|
|
||||||
|
memory_values = []
|
||||||
|
compare_values = []
|
||||||
|
|
||||||
|
for right_end in range(1, n, step):
|
||||||
|
AlgoDatValue.reset()
|
||||||
|
z = read_int_sequence_limited(filename, right_end)
|
||||||
|
tree = bt.BinTree()
|
||||||
|
for i in z:
|
||||||
|
tree.insert(i)
|
||||||
|
memory_values.append(AlgoDatValue.memory)
|
||||||
|
compare_values.append(AlgoDatValue.compare)
|
||||||
|
|
||||||
|
plt.plot(range(1, n, step), memory_values, 'b', label='Memory')
|
||||||
|
plt.plot(range(1, n, step), compare_values, 'r', label='Compare')
|
||||||
|
plt.legend()
|
||||||
|
plt.show()
|
Loading…
x
Reference in New Issue
Block a user