Problem Set 4 Solutions: Introduction To Algorithms
Problem Set 4 Solutions: Introduction To Algorithms
, where the elements are . There are 6 ways to insert the Exercise 4-1. Consider elements, but only 5 different trees. The tree with 2 at the root is created by two different insertion orders: and .
Exercise 4-2. The binary search tree property says that all elements to the left are smaller, and all to the right are larger. The min-heap property says that all elements both to the left and right are smaller. The min-heap property cannot be used to print out the keys of an -element heap in sorted order in time, because otherwise we could comparison sort in linear time: just build a heap of the elements ( time) and output them in sorted order (by assumption). This contradicts the comparison-model sorting lower bound of . Exercise 4-3. Consider the binary search tree as a graph with edges between each parent and its children. Every node (except the root) has a unique parent, so there are edges. Then the algorithm, as described, traverses each edge exactly once in each direction (once going down, the other going up), for a total of twice per edge. This takes time, as desired. Exercise 4-4. No, deletion is not commutative. To see why, consider the tree with root 5, children 3 and 7, and 6 as a child of 7. We will delete 5 and 3: if 5 is deleted rst, then we get the tree with root 6, children 3 and 7; after deleting 3 we get the tree with root 6 and right child 7. If 3 is deleted rst, 5 remains the root with only a right child; after deleting 5 we get the tree with root 7 and left child 6. Exercise 4-5. The CPU time with linear search is . With binary search, the becomes for a total CPU time of . By change of base, we know that , so as desired. Exercise 4-6. Consider the shortest simple path from to a descendant leaf, which has length ; then it contains at most black nodes. Any other simple path from to a descendant leaf has the same number of black nodes, and cannot have two red nodes in a row. Therefore it has length at most , as desired. Exercise 4-7. Every rotation (left or right) is determined by two vertices which have a parentchild relationship, and vice-versa. Every node (except the root) has a unique parent, so the number of parent-child pairs is exactly , yielding possible rotations.
(a) Given a string to insert into the trie, we do the following: follow the search procedure, creating a new node (with counter zero) whenever the appropriate child does not yet exist. At the nal node, increment its counter. The running time is (where is the length of the string), and does not depend at all upon the number of strings stored in the trie. (b) First, insert all of the strings of into a trie. Next, do a preorder tree walk of the trie (where we rst visit the root, then recursively visit the left subtree, then the right subtree), keeping track of the string corresponding to the current node. More specically, every time we descend from a parent to a left (or right) child, we append a 0 (or 1) to the current string; every time we ascend to a parent, we strip off the last character of the current string. When visiting each node, we output copies of the current string, where is the count of the node. The correctness of the algorithm comes from the preorder walk. It is easy to see that a nodes string lexically precedes all of the strings of its left subtree, and all of those strings precede all of the strings in the right subtree. For the running time, note that inserting all of the strings into a trie takes time, by the previous part. Printing out all of the strings also takes time, so we need only analyze the running time of the preorder walk. Note that there are at most different strings (because none of the strings have length 0, by the problem description), so there are at most unique nodes in the trie. Therefore a tree walk takes time because each edge in the trie is traversed exactly twice (once down, once up), and there are at most edges. So we get that the running time of the sorting algorithm is .
(c) This sorting algorithm would take time, when given inputs of the following form: copies of the string 0, and one string of length that consists of all 0s. (The zeros are not important; only the lengths are.) After padding, we are left with about strings each of length . R ADIX -S ORT takes time, where , , and . This simplies to .
Problem 4-2. Treaps (a) We prove this fact by (strong) induction. Clearly when , there is only one treap on elements when the key and score are xed. Assume now that for all , there is a unique treap. Suppose now that we have elements with xed (distinct) scores. Then there is some element which has the largest score, which must be the root of any treap on these elements (by the score-heap property). Now exactly those elements which are less than must go into the left subtree, and there are at most of them. By the inductive hypothesis, there is exactly one treap of those elements forming the left subtree. Likewise, there is exactly one treap of the elements greater than for the
(b) We have seen that once the scores are xed, there is exactly one treap that results, regardless of insertion order. Notice also that if we set all the scores ahead of time, inserting the elements in decreasing order of scores into a binary search tree will yield the treap (because new elements are always inserted below existing ones). Because the scores are random, every permutation of the elements (when put in decreasing order of score) is equally likely, so the treap with random scores is identical to a binary search tree with the elements inserted in random order. We have seen in class that a binary search tree has expected height when the elements are inserted in random order; therefore a treap has expected height when the scores are assigned randomly. (c) The main idea is the following: rst we insert the element with BST-I NSERT (which ensures that the data structure has the BST property), which may violate the heap property. Then we use rotations to x-up these violations, while retaining the BST property. More specically, the algorithm is the following: to insert an element into the trie, rst insert it using BST-I NSERT . Then if s score is larger than its parents score, do a rotation of the proper type around s parent (if is a right child, do a left rotation; if is a left child, do a right rotation). Repeat until s score is less than its parents, or until is at the root of the trie. Now we argue correctness: after insertion, the trie is still a binary search tree on the elements, and rotations preserve this property. Furthermore, after insertion the only violation of the heap property (that is: each nodes score is larger than both of its childrens scores) can be between and its parent. It is easy to verify that performing a rotation puts above its old parent, and does not introduce any new violations of the heap property, except possibly between and its new parent. Therefore our algorithm preserves both the BST and heap properties, which means the data structure remains a treap. For running time, note that the normal BST insertion requires time, where is the height of the tree (and is in expectation). The number of rotations we do is also at most , so the total running time is . (In fact, it can be proven that the expected number of rotations per insert is at most 2, though this doesnt improve the asymptotic running time.) Problem 4-3. Modied B-trees (a) To S EARCH for a key in a modied B-tree, start at the root. Check each of the children in order, and recursively S EARCH for in the last child whose minimum leaf is at most (if the rst childs minimum is greater than , then is not in the tree). At the leaf level, return the leaf only if its key is .
Problem 4-4. Rotations (a) Suppose we are right-rotating around , which has left child and right-subtree , where has right- and left-subtrees and , respectively. The right-rotation does not change for any that is outside the subtree orignally rooted at , so we need only examine how changes on that subtree. Let be the number of elements in a tree . Before the rotation, by simply adding , , and of each subtree. After the rotation , so it decreases by as desired.
(b) Note that for a left-path tree , , and for a right-path tree , . Also note that in the notation from the previous part, a right-rotation decreases by . Therefore it is enough to perform a series of right-rotations, where each respective is an empty tree; this series would include right-rotations. This is indeed possible: for any tree, consider the set of all nodes that have non-empty left subtrees. If the tree is not a right-path, then this set is non-empty. Therefore it has some node with largest depth, which has left child . Then has no left child (otherwise would be in the set and have larger depth than ), so a right-rotation around decreases by only 1, as desired.
(c) We can turn any tree into a right-path with at most rotations, by increasing the number of nodes on the right spine (those elements reachable from the root by following only right children) with each rotation. Note that initially the right spine contains at least one element (the root itself). In addition, if the tree is not a right-path, then there is some element which is the left child of an element on the right spine. We can then right-rotate around , which adds to the right spine without removing any other nodes from it. Hence, the number of elements on the right spine increases by one. Therefore after at most rotations of this type, the right-spine has nodes and is, in fact, a right-path. To turn any tree into any other tree , rst turn into a right-path using at most right-rotations. Then consider how would be turned into a right-path using at most right-rotations; from the right-path (obtained from ), do the corresponding left-rotations in reverse order to arrive at . This process requires at most rotations total, as desired.