Lecture06 Binary Trees I
What’s a Binary Tree?
- Pointer-based data structures (like Liked List) can achieve worst case
- Binary tree is pointer-based data structure with three pointers per node.
- Node representation:
node.{item, parent, left, right}
- Implement:
class Binary_Node:
def __init__(A, x): # O(1)
A.item = x
A.left = None
A.right = None
A.parent = None
# A.subtree_update() # wait for R07!
Terminology of a Binary Tree
- Root - The root of a tree has no parent
- Leaf - A leaf of a tree has no children
- Depth - Define depth(
<X>
) of node<X>
in a tree rooted at<R>
to be length of path from<X>
to<R>
[from up to bottom (max)] - Height - Define height(
<X>
) of node<X>
to be max depth of ant node in the subtree rooted at<X>
[from bottom to up] - Traversal Order
- every node in node
<X>
's left subtree is before<X>
- every node in node
<X>
's right subtree is after<X>
- every node in node
- List nodes
def subtree_iter(A): # O(n)
if A.left: yield from A.left.subtree_iter()
yield
if A.right: yield from A.right.subtree_iter()
Tree Navigation
-
Find first node in the traversal order of node
<X>
's subtree-
If
<X>
has left child, recursively return the first node in the left subtree -
Else,
<X>
is the first node, so return it -
Implement:
def subtree_first(A): # O(h) if A.left: return A.left.subtree_first() else: return A def subtree_last(A): # O(h) if A.right: return A.right.subtree_last() else: return A
-
-
Find successor of node
<X>
in the traversal order- If
<X>
has a right child, return first of right subtree - Else, return lowest ancestor of
<X>
for which<X>
is in its left subtree - Implement:
def successor(A): # O(h) if A.right: return A.right.subtree_first() while A.parent and (A is A.parent.right): A = A.parent return A.parent
- If
Dynamic Operations
-
Change the tree by a single item (only add or remove leaves):
- add a node after another in the traversal order (before is symmetric)
- remove an item from the tree
-
Insert node
<Y>
after node<X>
in the traversal order-
If
<X>
has no right child, make<Y>
the right child of<X>
-
Else, make
<Y>
the left child of<X>
’s successor (which cannot have a left child) -
Implement:
def subtree_insert_before(A, B): # O(h) if A.left: A = A.left.subtree_last() A.right, B.parent = B, A else: A.left, B.parent = B, A # A.maintain() # wait for R07! def subtree_insert_after(A, B): # O(h) if A.right: A = A.right.subtree_first() A.left, B.parent = B, A else: A.right, B.parent = B, A # A.maintain() # wait for R07!
-
-
Delete the item in node
<X>
from<X>
’s subtree-
If
<X>
is a leaf, detach from parent and return -
Else,
<X>
has a child- If
<X>
has a left child, swap items with the predecessor of<X>
and recurse - Otherwise
<X>
has a right child, swap items with the successor of<X>
and recurse
- If
-
Implement:
def subtree_delete(A): # O(h) if A.left or A.right: # A is not a leaf 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: # A is a leaf if A.parent.left is A: A.parent.left = None else: A.parent.right = None # A.parent.maintain() # wait for R07 return A
-
Binary Node Full Implementation
class Binary_Node:
def __init__(A, x): # O(1)
A.item = x
A.left = None
A.right = None
A.parent = None
# A.subtree_update() # wait for R07!
def subtree_iter(A): # O(n)
if A.left: yield from A.left.subtree_iter()
yield
if A.right: yield from A.right.subtree_iter()
def subtree_first(A): # O(h)
if A.left: return A.left.subtree_first()
else: return A
def subtree_last(A): # O(h)
if A.right: return A.right.subtree_last()
else: return A
def successor(A): # O(h)
if A.right: return A.right.subtree_first()
while A.parent and (A is A.parent.right):
A = A.parent
return A.parent
def predecessor(A): # O(h)
if A.left: return A.left.subtree_last()
while A.parent and (A is A.parent.left):
A = A.parent
return A.parent
def subtree_insert_before(A, B): # O(h)
if A.left:
A = A.left.subtree_last()
A.right, B.parent = B, A
else:
A.left, B.parent = B, A
# A.maintain() # wait for R07!
def subtree_insert_after(A, B): # O(h)
if A.right:
A = A.right.subtree_first()
A.left, B.parent = B, A
else:
A.right, B.parent = B, A
# A.maintain() # wait for R07!
def subtree_delete(A): # O(h)
if A.left or A.right: # A is not a leaf
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: # A is a leaf
if A.parent.left is A: A.parent.left = None
else: A.parent.right = None
# A.parent.maintain() # wait for R07
return A
Top-Level Data Structure
class Binary_Tree:
def __init__(T, Node_Type = Binary_Node):
T.root = None
T.size = 0
T.Node_Type = Node_Type
def __len__(T): return T.size
def __iter__(T):
if T.root:
for A in T.root.subtree_iter():
yield A.item