圖解-堆排序 in-place Heap Sort
轉自:http://www.mathcs.emory.edu/~cheung/Courses/171/Syllabus/9-BinTree/heap-sort2.html
- Short-coming of the previous "simple" Heap Sort algorithm
- Consider the (previously discussed) simple Heap Sort algorithm:
public static void main(String[] args) { Scanner in = new Scanner(System.in); double a[] = {9.2, 4.2, 1.1, 6.4, 3.5, 8.9, 2.5, 7.5}
This algorithm uses 2 (two) arrays:
- The array a[ ] to store the data that we want to sort
- The Heap data structure (that we create
- The array a[ ] to store the data that we want to sort
- Idea:
- Can we use the input array a[ ] as a Heap ???
In other words:
- Can we apply the heap insert/delete algorithm directly on the array a[ ] ???
- Can we use the input array a[ ] as a Heap ???
- Consider the (previously discussed) simple Heap Sort algorithm:
- Input data assumption
- Facts:
- The input data that will be sorted are normally stored in an array that starts with the index 0 in Java
- However:
- When we use an array to represent a Heap, we leave the array element a[0] unused (empty)...
- The input data that will be sorted are normally stored in an array that starts with the index 0 in Java
- We adopt the following assumption on the input data (that we want to sort) in the Heap Sort algorithm:
- The input data that will be sorted are stored in an array that starts with the index 1
(I.e., the array element a[0] is not used)
Example:
- If we want to sort the values:
9.2, 4.2, 1.1, 6.4, 3.5, 8.9, 2.5, 7.5
we will use an array with a dummy value in a[0]:
double[] a = { 0.0, 9.2, 4.2, 1.1, 6.4, 3.5, 8.9, 2.5, 7.5};
- The input data that will be sorted are stored in an array that starts with the index 1
- Facts:
- Overview of the in-place Heap Sort algorithm
- The in-place Heap Sort algorithm consists of 2 phases:
- Heap building (insert) phase:
- In this phase, the input array is slowly transformed into a Heap --- one array element at a time.
- Heap teardown (delete) phase:
- In this phase, the root node of the Heap is moved to the back of the array and the heap is torn down, one array element at a time.
- Heap building (insert) phase:
- The in-place Heap Sort algorithm consists of 2 phases:
- Heap Sort Phase 1: building an in-place heap
- I will illustrate the Phase 1 algorithm with an example:
Input array: a = { 0.0, 9.2, 4.2, 1.1, 6.4, 3.5, 8.9, 2.5, 7.5};
- We pretend that the input array is partitioned into 2 segments:
- A heap segment consisting of the array elements:
a[1] a[2] .... a[k]
that form a Heap
- A unprocessed segment of unprocessed array elements:
a[k+1] a[k+2] .... a[N]
- A heap segment consisting of the array elements:
- Initially, the heap segments consists of only one array element (a[0]):
- I will now do a few iterations of the Phase 1 algorithm:
- Iteration 1:
- Step 1: add the next array element (a[2] = 4.2) to the Heap
- Step 2: Filter the newly added next array element (a[2] = 4.2) up into the Heap
- Step 1: add the next array element (a[2] = 4.2) to the Heap
- Iteration 2:
- Step 1: add the next array element (a[3] = 1.1) to the Heap
- Step 2: Filter the newly added next array element (a[3] = 1.1) up into the Heap
- Step 1: add the next array element (a[3] = 1.1) to the Heap
- One more and I will stop, Iteration 3:
- Step 1: add the next array element (a[4] = 6.4) to the Heap
- Step 2: Filter the newly added next array element (a[4] = 6.4) up into the Heap
- Step 1: add the next array element (a[4] = 6.4) to the Heap
- Iteration 1:
- The Phase 1 of the Heap Sort algorithm:
// Initially: heap segment = {a[1]} for ( every element x = a[2], a[3], a[4], .... ) { "Include x into the Heap;" // We don't need to do anything !!! // We just pretend the heap segment // has expanded by 1 array element filter x up the heap; }
- The Phase 1 algorithm in Java:
NNodes = 1; // Start the Heap with a[1] for (i = 2; i < a.length; i++) { NNodes++; // "Include" the next node HeapFilterUp(a, NNodes); // Filter a[NNodes] up the heap. }
- I will illustrate the Phase 1 algorithm with an example:
- The result of the Phase 1 algorithm
- Fact:
- When Phase 1 of the Heap Sort algorithm completes, the input array (a[ ]) will be transformed into a Heap
- Example:
- Initial input array:
- When phase 1 completes, the input array will be a Heap:
- Initial input array:
- Fact:
- Heap Sort Pase 2: tearing down the in-place heap
- In Phase 2, we repeatedly remove the root node of the (in-place) heap
- The root node of the Heap is (always) stored in the array element a[1]
Example:
- The root node of the Heap is (always) stored in the array element a[1]
- Recall:
- When we delete a node from the Heap, we must first:
- Replace the deleted node with the right-most leaf node in the lowest level
Example:
- When we delete the root node 1.1:
- We first replace the root node with the node 6.4:
- When we delete a node from the Heap, we must first:
- The Heap deletion algorithm will then use the filter down algorithm to transform the tree into a Heap
(Remember that in a Heap, the root node of each subtree must have the smallest value in its subtree -
The filter down algorithm will fix the tree to comply with this property)
- We can (and will) apply the filter down algorithm to fix the tree...
(We will discuss that later...)
But more importantly, notice that:
The array has a empty slot at the end !!!
- We can use this empty slot to store the deleted value (1.1) !!!
(This trick makes the Heap Sort algorithm an in-place algorithm --- we don't need another array !!!)
- We can use this empty slot to store the deleted value (1.1) !!!
- We can (and will) apply the filter down algorithm to fix the tree...
- This is what I mean:
- We store the deleted value into the empty slot created by the replacement step of the Heap deletion algorithm:
- We store the deleted value into the empty slot created by the replacement step of the Heap deletion algorithm:
- Now we perform the filter down algorithm to fix the Heap:
- Initially:
- Filter down: swap with the smallest child node
Result:
- Since 6.4 is smaller than its children nodes (9.2 and 7.5), we have a Heap again.
- Initially:
- I will now do one more iteration of the Phase 2 algorithm (starting with the last result):
- Iteration 2: (the previous iteration was the first iteration !)
- Initially:
- Delete the root node (a[1]):
(We save the deleted value in a help variable)
- Replace the root node with the fartest right node on the lowest levl:
(We save the deleted value in a help variable)
- Save the deleted value in the empty slot: (this slot is not part of the Heap !!!)
- Fix the Heap using the filter down algorithm:
Exchange the replacement node with its smallest child:
Result:
Exchange again: (because one of its child node is smaller)
Result:
- Initially:
- Iteration 2: (the previous iteration was the first iteration !)
- Notice that:
- The value is sorted backwards in the back of the array !!!
Example:
- The value is sorted backwards in the back of the array !!!
- Phase 2 algorithm in Pseudo code:
repeat these step N times (N = # nodes in the heap) { help = a[1]; // Delete the root node and save the value a[1] = a[last node in heap]; // Replace root node with // fartest right node on lowest level a[empty slot] = help; // Save deleted value in empty slot HeapFilterUp( 1 ); // Fix the heap start at root node } // Optionally, we can reverse the // array elements (because the values are sorted in reverse order)
- Phase 2 algorithm in Java:
for ( i = 1; i < a.length; i++ ) { help = a[1]; // Delete root node a[1] = a[NNodes]; // Replace root node with the last node a[NNodes] = help; // Put the deleted node in the empty slot NNodes--; // One less node in Heap HeapFilterDown(a, 1, NNodes); // Fix the Heap } /* ========================================================= This for-loop reverse the elements a[1] a[2] ... a[N] ========================================================= */ for ( i = 1, j = a.length-1; i < j; i++, j-- ) { help = a[i]; a[i] = a[j]; a[j] = help; }
- In Phase 2, we repeatedly remove the root node of the (in-place) heap
- The complete Heap Sort algorithm
- Putting phase 1 and phase 2 into the sort method yields the following code:
public static void sort( double[] a ) { int i, j, NNodes; double help; /* ======================================= Phase 1 ======================================= */ NNodes = 1; for (i = 2; i < a.length; i++) { NNodes++; // include next node HeapFilterUp(a, NNodes); printHeap(a, NNodes); } /* ======================================= Phase 2 ======================================= */ for ( i = 1; i < a.length; i++ ) { help = a[1]; // Delete root node a[1] = a[NNodes]; // Replace root node with the last node a[NNodes] = help; // Put the deleted node in the empty slot NNodes--; // One less node in Heap HeapFilterDown(a, 1, NNodes); // Fix the Heap printHeap(a, NNodes); } /* ======================================= Reverse the (sorted) array ======================================= */ for ( i = 1, j = a.length-1; i < j; i++, j-- ) { help = a[i]; a[i] = a[j]; a[j] = help; } }
- The Filter Up method has been changed a little (because we must pass the array as a parameter)
The array a is passed as parameter The parameter k also to tell the method how many nodes there are in the Heap public static void HeapFilterUp( double[] a, int k ) { **** The BODY of the method is UNCHANGED !!!! **** }
(The algorithm did not change. --- that's why I did not include the body)
Only the way that the array is given to the method was changed
This change does not (and should not) affect you understanding of the algorithm !!!)
- The Filter Down method is also change a little bit due to the way the parameters are passed:
The array a is passed as parameter The parameter NNodes is also needed to tell the method how many nodes there are in the Heap (k is the index of the delete location) public static void HeapFilterDown( double[] a, int k, int NNodes ) { **** The BODY of the method is UNCHANGED !!!! **** }
- Here is a test program for the Heap Sort method:
public static void main( String[] args ) { double[] x = {0, 6.4, 2.5, 9.2, 3.5, 8.9, 1.1, 7.5, 4.2} ; System.out.println("Before sort: " + Arrays.toString(x) + "\n" ); HeapSort.sort( x ); // Heap sort System.out.println("\nAfter sort: " + Arrays.toString(x) ); }
Output:
After sort: [0.0, 1.1, 2.5, 3.5, 4.2, 6.4, 7.5, 8.9, 9.2]
- Example Program: (Demo above code)
- The Heap Sort Prog file: click here
- The test Prog file: click here
How to run the program:
- Right click on link and save in a scratch directory
- To compile: javac testProg.java
- To run: java testProg
- Putting phase 1 and phase 2 into the sort method yields the following code: