Binary tree:
def:
pointer-based data structure,it has three pointers each node.
Binary tree is a tree of binary nodes.
representation:
node.{item,parent,left,right}
Initialiaze:
class Binary_Node:
def __init__(self, A, x):
A.item = x
A.left = None
A.right = None
A.parent = None
Binary tree & Linked list:
In the linked list, we may cost time to get a item.
In the binary tree, which height is h.We only take time to get one. Thus that,we can take operations faster in binary tree.
Tree Navigation:
Traversal Order:
X.left_subtree -> X -> X.right_subtree
def subtree_iter(A):
if A.left: yield from A.left.subtree_iter()
yield A
if A.right: yield from A.right.subtree_iter()
Find first node:
- If x has left child,recursively return the first node in the left subtree.
- Otherwise,x is the first node.
def subtree_first(A):
if A.left:
A.left.subtree_first
else:
return A
def subtree_last(A):
if A.right:
A.right.subtree_last
else:
return A
Find successor:
- If x has right child, return thefirst node in the right subtree
- Otherwise,return the low ancestor of x,for which,x is in the left subtree
def successor(A):
if A.right:
return A.right.subtree_first()
else:
while A.parents and A is (A.parens.right):
A = A.parents
def predecessor(A):
if A.left:
return A.left.subtree_last()
else:
while A.parents and (A is A.parents.right):
A = A.parents
Dynamic Operatins:
Insert:(insert < y > after < x >)
- If < x > has no right child,make < y > the right child of < x >
- Otherwise, make< y > the left child of < x>'s successor(which doesn't have left node)
def subtree_insert_before(A, B):
if A.left:
A = A.left.subtree_last
A.right, B.parent = B, A
else:
A.left, B.parent = B, A
A.maintain ()
def subtree_insert_after(A, B):
if A.right:
A = A.right.subtree_first
A.left, B.parent = B, A
else:
A.right, B.parent = B, A
A.maintain ()
Delete:
The key is that,if the node is leaf ,it's easy to delete.
If the node isn't a leaf node , just make it to leaf. What we need to do is swapping it with it's child,then recurse to be the leaf node.
- If x is leaf node,delete it dirrectly
- else if x has left child,swap it with it's predeccessor,and recurse
- else if x has right child,swap it with it's successor,and recurse
def subtree_delete(A):
if A.parent():
if A is A.parent.left:
A.parent.left = None
else:
A.parent.right = None
A.parents.maintain()
if A.left or A.right:
if A.left:
B = A.predecessor()
else:
B = A.successor
A.item, B.item = B.item, A.item
return B.subtree_delete()
Application Set:
Set Binary tree:(Binary Search Tree)
BST Property:
We can use the binary seaerch to find the key k.
- If k is samller than x.key,recurse in left subtree
- If k is larger than x.key.recurse in the right subtree
- If k == x.key,x is the item we find
class Binary_Search_Tree_Node(Binary_Node):
def subtree_find(A, k):
if k < A.item.key:
if A.left: return A.left.subtree_find(k)
if k > A.item.key:
if A.right: return A.right.subtree_find(k)
else:
return A
def subtree_find_next(A, k):
if k >= A.item.key:
if A.right:
return A.right.subtree_find_next(k)
else:
return None
elif A.left:
B = A.left.subtree_find_next(k)
if B: return B
else:
return A
def subtree_find_prev(A, k):
if k <= A.item.key:
if A.left:
return A.left.subtree_find_prev(k)
elif A.right:
B = A.right.subtree_find_prev(k)
if B: return B
else:
return A
def subtree_insert(A, B):
if B.item.key < A.item.key:
if A.left:
A.left.subtree_insert(B)
else:
A.subtree_insert_before(B)
elif B.item.key > A.item.key:
if A.right:
A.right.subtree_insert(B)
else:
A.subtree_insert_after(B)
else:
A.item = B.item
class Set_binary_tree(Binary_Search_Tree_Node):
def __init__(self):
super().__init__(Binary_Search_Tree_Node)
def iter_order(self):
yield from self
def build(self, X):
for x in X:
self.insert(x)
def find_min(self):
if self.root:
return self.root.subtree_first()
def find_max(self):
if self.root:
return self.root.subtree_last
def find(self, k):
if self.root:
node = self.root.subtree_find(k)
if node:
return node.item
def find_next(self, k):
if self.root:
node = self.root.subtree_find_next(k)
if node:
return node.item
def find_prev(self, k):
if self.root:
node = self.root.subtree_find_prev(k)
if node:
return node.item
def insert(self, x):
new_node = self.Node_Type(x)
if self.root:
self.root.subtree_insert(new_node)
if new_node.parents is None: return False
else:
self.root = new_node
self.size += 1
return True
def delete(self, x):
assert self.root
node = self.root.subtree_find(k)
assert node
ext = node.subtree_delete(node)
if ext.parent is None: self.root = None
self.size -= 1
return ext
Application Sequence:
Sequence Binary Tree: Traversal order is sequence order
Maintain the size of each node's subtree at the node via augmentation.
- add node.size field to each node
- when adding new node,size+=1
- when deleting the node,size-=1
We can surmise the approxiamate place in the binary tree.
- define is the size of left subtree
- if i ,recurse in the left subtree
- else recurse in the right subtree,
Full Implementation:
class Binary_node:
def __init__(self, A, x):
A.item = x
A.left = None
A.right = None
A.parent = None
A.subtree_update()
def subtree_iter(self, A):
if A.left: yield from A.left.subtree_iter()
yield A
if A.right: yield from A.right.subtree_iter()
def subtree_first(self, A):
if A.left:
return A.left.subtree_first()
else:
return A
def subtree_last(A):
if A.right:
return A.right.subtree_last()
else:
return A
def successor(A):
if A.right: return A.right.subtree_first()
while A.parent and A.parent.right is A:
A = A.parent
return A.parent
def predecessor(A):
if A.left: return A.left.subtree_last()
while A.parent and (A.parent.left is A):
A = A.parent
return A.parent()
def subtree_insert_before(A, B):
if A.left:
A = A.left.subtree_last()
A.right, B.parent = B, A
else:
A.left, B = B, A
def subtree_insert_after(A, B):
if A.right:
A = A.right.subtree_first()
A.right = B
B.parent = A
else:
A.right = B
B.parent = A
def subtree_delete(A):
if A.left or A.right:
if A.left:
B = A.predecessor()
else:
B = A.successor()
A.item, B.item = B.item, A.item
return B.subtree_delete()
if A.parent:
if A.parent.left is A:
A.parent.left = None
else:
A.parent.right = None
return A
Exercise:
- Construct a binary tree,in order that,(1):the item of the tree is A[i],(2):T has height of
solution:The key is that, we maintain the middle ietem of the array as the root in the binary tree,and then recursively in the left and right subtree.
def build(X):
A = [x for x in X]
def build_subtree(A, i, j):
c = (i + j) // 2
root = self.Node_Type(A[c])
if i < c:
root.left.build_subtree(A, i, c - 1)
root.left.parent = root
if j > c:
root.right.build_subtree(A, c + 1, j)
root.right.parent = root
return root
self.root = build_subtree(A, 0, len(A) - 1)
- Analyse the running time of this code,the iterative procedure to return the nodes in order
def subtree_iter(A):
node = A.subtree_first
while node:
yield node
node = node.successor
Traverse each edge twice,once going down,once going back.The number of the edges is less than node's,so running time is