ICS 311 Spring 2004 HWK Solution 6.1-5 Yes, if sorted in increasing order. 6.1-6 No, nodes with values 6 and 7 violate the max-heap property. 6.1-7 In a heap of size n, leaves are nodes floor(n/2) + 1, floor(n/2) +2, …, n. Proof: A leaf node has no children. In a heap, if a node has no left child, it has no children. For a node i in a heap, LeftChild(i) = 2i. The smallest i for which 2i>heapsize holds true, where heapsize=n, is floor(n/2)+1. 6.2-1 A = 27 17 10 16 13 9 1 5 7 12 4 8 3 6.2-2 The code for MinHeapify is the mirror image of MaxHeapify. Running time of MaxHeapify is the same as for MinHeapify. MinHeapify(A, k) L = Left(k) R = Right(k) if L heapsize(A) and A[L] < A[k] smallest = L else smallest = k if R heapsize(A) and A[R] < A[smallest] smallest = R if smallest k exchange A[k] and A[smallest] MinHeapify(A, smallest) 6.2-4 Since nodes i > heap-size(A) / 2 are all leaves (see problem 6.1-7), MaxHeapify(A, i) will have no effect – the leaves do not need to be heapified. 6.4-1. Heapsort(A), A = <5,13,2,25,7,17,20,8,4> Build max-heap: 5 5 13 25 8 2 7 4 17 5 13 20 25 8 20 7 4 17 25 25 2 13 8 20 7 4 17 13 2 8 5 20 7 4 17 2 Start the for loop: 4 20 13 8 20 5 7 17 13 2 8 25 5 2 8 17 7 4 20 25 7 13 17 7 17 20 25 5 4 2 5 2 20 25 8 4 5 7 25 13 17 20 25 2 4 13 8 5 4 5 2 13 2 20 8 7 4 8 13 5 2 7 17 4 13 17 17 7 4 2 8 5 7 8 13 17 4 5 20 25 7 8 2 13 17 20 25 Final A = <2,4,5,7,8,13,17,20,25> 6.4-2 Heapsort for loop LI: subarray A[1, … i] is a max-heap containing the i smallest elements of A[1, ..n] and the subarray A[i+1, … n] contains the n-i largest elements of A[1, …n]. Proof: Prove for initialization, maintenance, and termination. Initialization (i=n): A[1,…n] is a max heap because we just called BuildMaxHeap. A[1, …n] contains the n smallest elements of A[1, …n], and A[n+1, …n] is an undefined array, so by the trivial case it contains n-n=0 largest elements of A[1, …n]. Maintenance (i = n-1, n-2, …. 2): array A[1, …i] is a max heap because we call MaxHeapify before entering the loop. A[1, …i] is the max-heap of smallest elements. The largest elements have been extracted out of the heap and are stored in increasing order in A[i+1, …n]. Termination (i = 1): A[1, …1] is one element heap, so it is a max-heap, and it contains the smallest element of A[1, ….n]. The rest of the array contains the largest elements in increasing order. 6.5-1 A = 15 13 9 5 12 8 7 4 0 6 2 1 becomes 13 12 9 5 6 8 7 4 0 1 2 , and 15 is returned. 6.5-2 MaxHeapInsert(A,10), A=<15,13,9,5,12,8,7,4,0,6,2,1> 15 15 13 5 4 6-2 9 12 06 8 21 13 7 10 5 4 9 12 06 15 21 13 10 7 8 5 4 10 12 06 9 21 7 8 Complete d-ary heap is an almost complete d-ary tree: each internal node has d children. Node 1 is the root. Children of node 1 are at nodes 2,3, …, d+1. Children of node 2 are at nodes (d+1) +1, …, (d+1) +d. Children of node 3 are at nodes (2d+1)+1, …, (2d+1)+d. Children of node i are at nodes (i-1)d+1+1, …, (i-1)d+1+d. jth child of node i is at node (i-1)d+1+j, where 1≤ j ≤ d. Therefore, d-ary child j of node i is found as d_aryChild(i,j) = (i-1)d+1+j. So, nodes (k-1)d+1+1, …, (k-1)d+1+d have parent at node k. Therefore, k = d-aryParent(z) = floor((z-2)/d + 1), where z = (k-1)d+1+1, …, (k-1)d+1+d. Check: d_aryParent(d_aryChild(i,j)) = i. Check: do we get the binary heap formulas for d=2? b) For a d-ary complete tree of total n nodes: At level 0, we have 1 node (the root). At level 2, we have d nodes. At level 3, we have d2 nodes. At level h, we have dh nodes, where h is the height of the tree. So, n = ∑ di , where i = 0, ..,h. According to the Appendix, this sum evaluates to n = (dh+1 -1) / (d –1). h+1 = logd (n(d-1) +1) h = logd (n(d-1) +1) -1 h = Θ (logd n) c) d_aryHeapMaxExtract(A) { //the code is the same as for HeapMaxExtract, except that //we use d_aryMaxHeapify } d_aryMaxHeapify(A, i) { //pseudocode is the same as MaxHeapify, except that in this function we //must compare i to all d children of i, not only 2 children child1=d_aryChild(i,1) child2=d_aryChild(i,2) … childd=d_aryChild(i,d) if A[child1] > A[i] largest = child1 else largest = i if A[child2] > A[largest] largest = child2 … if A[childd] > A[largest] Largest = childd if largest ≠ i, exchange A[i] and A[largest] d_aryMaxHeapify(A, largest) Running time of Maxheapify is O(lgn). Running time for d_aryMaxHeapify is O(d logd n), i.e. the height of the tree multiplied with the number of children examined at each node (which is at most d). Running time for d_aryHeapMaxExtract is O(d logd n). d) d_aryHeapInsert is the same code as for MaxHeapInsert, except that Parent(i) will be replaced by d_aryParent(i). Therefore, the running time is Θ(height). For the d-ary heap, it is then Θ(logd n). e) d_aryHeapIncreaseKey(A,i,k) { // a slight modification of MaxHeapInsert A[i] = max(A[i], k) while (i>1 and A[d_aryParent(i)] < A[i]) exchange A[i] and A[d_aryParent(i)] i = d_aryParent(i) The worst case: traveling up the entire tree, Therefore, the running time is Θ(height). For the d-ary heap, it is then Θ(logd n). 6-1 BuildMaxHeap’(A) and BuildMaxHeap don’t produce the same heap out of the same array! Try it on the array from the book, or just simply array A=<1,2,3>. BuildMaxHeap’ works by building a heap starting from one element and inserting new elements. The heap sequence is: 1 -∞ 1 2 2 1 2 1 -∞ 213 312 BuildMaxHeap works by max heapifying from the bottom up, produces: 123 321