Binary Search Trees
Overview
- Goal: Accomplish dynamic set operations in O(h) time where h is tree height
- Operations: search, insert, delete,
- Data structure: Binary Search Tree
- Performance:
- Best case: O(lg n) for ...
- Worst case: O(n) for ...
- Implementation: Linked tree nodes: T.root, n.key, n.left, n.right, n.p
- T.root
- n.key
- n.left
- n.left
- n.p
- T.root.p = nil
BST Property
- If y is in left subtree of x, y.key ?? x.key
- If y is in right subtree of x, y.key ?? x.key
- Example: F / B, H / A, D, nil, K
In Order Traversals
- How would we list the elements of a BST in order?
- Algorithm: ...
- Correctness: induction and BST property
- Time: Θ(n)
- T(0) = c, time for empty tree
- Time for processing node = d
- Recurrence Relation: T(n) = T(k) + T(n-k-1) + d
- Guess: T(n) = (c+d)n + c
- n=0 yields c = T(0)
- Inductive step: ...
Search
- Find key k in tree rooted at node x
- Algorithm:
Search(x, k)
if x = nil or x.key = k then
return x
elsif k < x,key
return Search(x.left, k)
else
return Search(x.right, k)
Performance: O(?) where ? is ...
Tree Minimum an Maximum
- Where is the minimum value in a BST?
- Algorithm to find minimum:
Minimum(x)
while x.left /= nil loop
x := x.left
end loop
return x
What about code for the maximum?
Performance: O(h) where ? is ...
Successor
- Where is the successor to value in node x to be found?
- If x has a non-empty right subtree, x's successor is the
minimum of the x.right subtree
- If x has an empty right subtree, x's successor y is the node
that x is the predecessor of (ie x is the maximum in y's left
subtree)
- Algorithm:
Successor(x)
if x.right /= nil then
succ := minimum(x.right)
else
succ := x.p
while succ /= nil and x = succ.right loop
x := succ
succ := succ.p
end loop
end if;
return succ
Example: 15 / 6, 18 / 3, 7, 17, 20 / 2, 4, nil, 13, 4*nil / 4*nil, -, 9, nil,
----
- Find successors of 15, 6
- Find predecessor of 4
Time: O(h)
Insertion
- Insert node z into tree T
- Must preserve BST property
- Algorithm:
Insert(T, z)
y := nil
x := T.root
while x /= nil loop
y := x
if z.key < x.key then
x := x.left
else
x := x.right
end if
end loop
z.p := y
if y = nil
T.root = z -- tree was empty
elsif z.key < y.key
y.left := z
else
y.right := z
end if
Insert(T,c) on F / B, H / A, D, nil, k
Time: O(h)
Delete
- Three cases:
- z has no children: remove z
- z has one child: move that child up
- z has 2 children: replace z by its successor (call the successor y)
- Where is y?
- y must be in z's right subtree and have no left child
- Algorithm uses Transplant, which replaces one subtree with another
Transplant
- Transplant(T, u, v) replaces subtree at u with subtree at v in T
- Algorithm:
Transplant(T, u, v)
if u.p = nil then -- Create a new root
T.root = v
elsif u = u.p.left then -- u was a left subtree
u.p.left := v
else -- u = u.p.left -- u was a right subtree
u.p.right := v
end if
if v /= nil then -- fix v's parent pointer
v.p = u.p
end if
Delete
Delete(T, z)
if z.left = nil then -- No left child
transplant(T, z, z.right)
elsif z.right = nil then -- No right child
transplant(T, z, z.left)
else -- z has 2 children
y := Minimum(z.right) -- y is z's successor
if y.p /= z then -- y is not z's right child
Transplant(T, y, y.right)
y.right := z.right
y.right.p := y
end if
Transplant(T, z, y)
y.left := z.left
y.left.p := y
end if
Example: H / B, I / A, G, nil, K / nil, E, nil, -, J, -, L, -, C, F, -, N
Time: O(h)
Minimizing h
- h = O(?)
- h = Ω(?)
- How do we guarantee good performance