CS 2223 Nov 12 2015
Expected reading: 315-320,323-327
Daily Exercise:
To have faith is to trust yourself to the water. When you swim you don’t grab hold of the water, because if you do you will sink and drown. Instead you relax, and float.
Alan Watts
1 HeapSort
Now that you have seen a Heap structure, we need to understand how to build a heap from scratch, and how it can be used in an interesting sorting algorithm called Heap Sort.
1.1 But first, HW2
No doubt, you have a lot of HW2 on your mind. Open questions here that I can try to answer.
The rubric is now posted so you can see where the points are going to be assigned.
1.2 Building a Heap
On page 318 of the book, you can see the disarmingly simple code for adding an element to a heap. In this case, we assume there is enough room in the array, but you should know how to add the necessary code to dynamically resize the array to add more space as needed.
public void insert (Key v) { pq[++N] = v; swim(N); }
This code first pre-increments N – recall that the 0th element of the array is not being used to make the indices easier to compute. Remember that a heap must maintain its Heap shape property, which means that you don’t add a new item to a level until the previous level is complete, and each level is filled from left to right in order. The pq[++N] = v statement does just that.
Once inserted, this new value might violate the Heap ordering property, so you have to invoke swim(N) to make sure that all ancestors are properly updated to abide by this property.
1.3 In-class exercise
Use this process to build a heap after the following values have been added in the following order:
2, 7, 4, 9, 8, 6
Assuming the array has enough room for the elements, what will be the final array representation in the resulting heap?
1.4 Removing an element from a Heap
Finding the largest element is not an issue becaue the topmost element in the heap a[1] is the largest value. However, once it is removed, what do we replace it with? I guess it could be replaced with the larger of its two children, but we have to be very careful to maintain the Heap Shape Property. Since adding to a heap was simply a matter of adding to the final unused element in the array, perhaps this remove operation could use that value as the replacement and then reduce the size of the heap by one.
public Key delMax() { Key max = pq[1]; exch(1, N−−); // swap final entry to replace root pq[N+1] = null; // to avoid loitering sink(1); // re-establish heap ordered property return max; }
Observe that the delMax operation reduces the number of elements in the array by one, and the Heap Shape Property is maintained by carefully mainpulating the elements. The sink(1) operation resetablishes the Heap Ordered Property and it takes no more than ~ log N operations to achieve this.
Given the final heap we just constructed, demonstrate the resulting array structure after invoking delMax two more times.
1.5 How to use Heap to implement sorting
First observe that the topmost element of the heap is always the largest item. This gives us our first clue. However, if we are to sort "in-place" without any additional storage, what can we do?
Start with an arbitrary array and convert it into a Heap. Note that we now have to ensure that the 0th array location is part of the heap, which is something we didn’t do earlier; however, nothing could be simpler!
The trick is to recognize that all elements are refered to only within the less and exch methods. Therefore, these two methods are changed as follows to reflect 1-based indexing. Thus the 1st element is to be found at index location 0.
static boolean less(Comparable[] a, int i, int j) { return a[i-1].compareTo(a[j-1]) < 0; } static void exch(Object[] a, int i, int j) { Object swap = a[i-1]; a[i-1] = a[j-1]; a[j-1] = swap; }
Note there are still N elements in the array, and they are referred to using 1-based indexing. Again, this was done by Sedgewick to make the computations easier to see and understand.
1.6 Ready to explain HeapSort
There are two steps that we complete. First we need to turn an arbitrary array of values into a Heap.
1.6.1 Convert arbitrary array into heap
Consider the following partial array of values. I use "??" to represent any number. If you look at the picture and squint, the numbers that are present could actually already be in their proper spot for all that you know! Or to put it in other words, each of these elements forms a valid heap of 1 element.
So where is the first element that has a child? If we start counting each element, starting with numbers 1, 2, 3, ... then the position is exactly located at index floor(N/2). See code on (p. 324).
So all we need to do is visit each of the ?? positions in reverse order and call sink on that location to reestablish the Heap ordering property. The code is just a bit more complex because you have to pass in more parameters. First you pass in the array that is being converted into a heap structure; then you pass in N the number of elements, so sink knows when to stop; and you pass in k representing the item location (when counting from 1) to sink:
static void sink(Comparable[] a, int k, int N) { while (2*k <= N) { int j = 2*k; if (j < N && less(a, j, j+1)) j++; if (!less(a, k, j)) break; exch(a, k, j); k = j; } }
This code should be familiar from yesterday. Once all floor(N/2) positions have been processed and the array has been turned into a Heap, the sorting process can begin.
1.6.2 Exchange largest into proper place
With just N-1 iterations, it is possible to sort the heap into an array. The largest element is always in the 1st location, so we first swap this with the final element in the heap and decrement the number of elements in the array. This results in an array of N-1 elements and all you need to do is reestablish the Heap Ordered Property starting with the 1st element. Here is what the full sorting code looks like:
public static void sort(Comparable[] a) { int N = a.length; for (int k = N/2; k >= 1; k−−) { // (1) Create Heap from array sink(a, k, N); show(a); } while (N > 1) { // (2) Modify in place, exch. max exch(a, 1, N−−); sink(a, 1, N); } }
We will work through example in class.
1.7 Tilde Notation
The book covers Tilde notation in pages 180-187 and this is the first place you should go to learn about this notation. You see this on homeworks HW2 and HW3 and you will see this topic on the exam.
There are two skills that you need to do:
Code Analysis: Given a block of code, analyze the order of growth (as a function of N) of the running time of the code fragment. Consider the following code. Think of the frequency of execution of the outer loop and the inner loops (see p. 181 for details).
int sum = 0; // Block A for (int n = N; n > 0; n /= 2) { // Block B for (int i = 0; i < n; i++) { // Block C sum++; } }
t1: A executes 1 time
t2: B executes ________ times
t3: C executes ________ times
Grand Total: ____________
Tilde Approximation aims to remove terms that will have decreasing impact as N grows.
The resulting Ordering Of Growth is going to be based on the formulae found on p. 187:
1 – constant
log N – logarithmic
N – linear
N log N – linearithmic
N2 – quadratic
N3 – cubic
bN – exponential (in any base b>1)
1.8 Daily Exercise
Without referring to any online or book resources, we are going to list a number of elements from a category. For example, we will start by naming all the plays of William Shakespeare (don’t peek!). Then we will try another category to see how we retrieve information from our own brains.
1.9 Sample Exam Question
The following exam question is just a bit too hard to ask on the exam. But try it out and we will review in the next lecture:
You have an array of N elements in sorted order. You wish to use Binary Array Search to determine the rank for a target value, x. The only problem is, the compareTo(a, b) operator will lie exactly one time during your search. This function returns 0 if the values are the same, a negative number if a < b, and a positive number if a > b.
Complete the following skeleton algorithm (in pseudo code or Java code) and then identify the fewest number of less requests that your algorithm needs to accurately determine the rank of x.
(a) Design your algorithm in Java or pseudo code
int rank (Comparable[] a, Comparable x) { // fill in here... }
(b) Compute the fewest number of less requests needed in terms of N where N is the number of elements in the Comparable[] array.
1.10 Version : 2014/02/05
(c) 2015, George Heineman