CS 361 – Chapter 3 Sorted dictionary ADT Implementation –Sorted array –Binary search tree
Sorted Dictionary Still want to access elements by their key value. Also: maintain elements “in order”. Besides insert, delete, find, we add these functions: –predecessor (x) –successor (x) Generalization: in case x is itself not in the dictionary –closestBefore (x) –closestAfter (x)
Implementation A hash table would not be good –Since elements not sorted in any way, searching would be a waste of time. A simple implementation: sorted table/array –Insert & delete operations require shifting. √ –Search: binary search strategy runs in O(log n) time. Cut the search space in half until you find value, or conclude it doesn’t exist. Does this list contain 52? 5,8,12, 13, 15, 18, 20, 25, 30, 32, 36, 38, 44, 45, 58, 61, 62, 77, 80 –This is how a spell checker works. –Finding the pred/succ also O(log n).
Implementation #2 The classic way to implement a sorted dictionary ADT is the binary search tree. Seeks to make insert & delete more efficient than sorted table. Properties of BST –For all nodes: left child you right child –Or better yet: all in L subtree you all elements in R subtree –Not a heap: no restriction on height. Internal rep’n may be array, but: –Convenient to conceive of logically as a tree. –Unlike a heap, array would be space-inefficient.
BST functions To understand BST, we should consider how to: Search for a key value Find the max and min values Find the pred or succ Insert Delete
Search, min, max Search(k) –Just follow binary search strategy. –Starting at root, follow left or right child… until you find k or discover it can’t exist. –May be recursive or just a while loop. Next, how would you find …? –Min key value in the tree –Max key value in the tree
Successor Pred & succ are analogous/symmetric cases, so let’s just look at successor function. Try example. succ(x): if right(x) not empty return min(right(x)) else // succ is lowest ancestor of x whose // left child is also ancestor of x y = parent(x) while y && x == right(y) x = y y = parent(x) return y The while loop goes up the tree until x is the left child of its parent
Insert, delete Insert(k) is like search –The new key becomes a left/right child as appropriate. –Special case if tree initially empty. Delete(victim) – Careful… there are 3 cases, depending on how many children the victim has. –If victim has no children: it’s a leaf. Just tell parent to set its left or right child pointer to null. –If victim has 1 child: Reset its parent and child to point to each other now. –What if victim has 2 children?
Delete, continued Deleting a node that has 2 children: –Replace the victim with succ(victim) –Now, need to repair pointers where succ(victim) came from. Turns out that succ(victim) has at most 1 child. It can’t have a left child… if it did, then it’s not really the succ. Go back to how we calculated succ(x) to see why it’s true. So, treat the removal of succ(victim) like the 0 or 1 child delete case. Try example