Like merge sort, but unlike insertion sort, heapsort's running time is O(n lg n). Like insertion sort, but unlike merge sort, heapsort sorts in place: only a constant number of array elements are stored outside the input array at any time. Thus, heapsort combines the better attributes of the two sorting algorithms we have already discussed.
Heapsort also introduces another algorithm design technique: the use of data structure, in this case one we call a "heap", to manage information during the execution of the algorithm. Not only is the heap data structure useful for heapsort, but it also makes an effecient priority queue.
We note that the term "heap" was originally coined in the context of heapsort, but it has since come to refer to "garbage-collected storage:, such as the programming languages Lisp and Java provide. Our heap data structure is not garbage-collected storage, and whenever we refer to heaps here, we shall mean the structure.
The (binary) heap data structure is an array object that can be viewed as a nearly complete binary tree. Each node of the tree corresponds to an element of the array that stores the value in the node. The tree is completely, filled on all levels except possibly the lowest, which is filled from the left up to a point.
The root of the tree is A[1], and given the index i of a node, the indicies of its parent PARENT(i), left child LEFT(i) and right child RIGHT(i) can be computed simply.
PARENT(i)
return floor[ i/2 ]
LEFT(i)
return 2i
RIGHT(i)
return 2i + 1
On most computers, the LEFT procedure can compute 2i in one instruction by simply shifting the binary representation of i left one bit position. Similarly, the RIGHT procedure can quickly compute 2i + 1 by shifting the binary representation of i left one bit position and adding in a 1 as the low-order bit. The PARENT procedure can compute floor[ i/2 ] by shifting i right one bit position. In a good implementation of heapsort, these three procedures are often implemented as "macro" or "in-line" procedures.
There are two kinds of binary heaps: max-heaps and min-heaps. In both kinds, the values in the nodes satisfy a heap property, the specifics of which depend on the kind of heap. In a max-heap, the max-heap property is that for every node i other than the root,
A[PARENT(i)] ≧ A[i],
that is, the value of a node is at most the value of its parent. Thus, the largest element in a max-heap is stored at the root, and the sub-tree rooted at a node contains values no longer than that contained at the node itself. A min-heap is organized in the opposite way: the min-heap property is that for every node i other than the root,
A[PARENT(i)] ≦ A[i].
The smallest element in a min-heap is at the root.
For the heapsort algorithm, we use max-heaps. Min-heaps are commonly used in priority queues. We shall be precise in specifying whether we need a max-heap or a min-heap for any particular application, and when properties apply to either max-heaps or min-heaps, we just use the term "heap".
Viewing a heap as a tree, we define the height of a node in a heap to be the number of edges on the longest simple downward path from the node to a leaf, and we define the height of the heap to be the height of its root. Since a heap of n elements is based on a complete binary tree, its height is Θ(lg n). We shall see that the basic operations on heaps run in time at most proportional to the height o the tree and thus take O(lg n) time. The reminder of this article presents ive basic procedures and shows how they are used iun a strong algorithm and a priority-queue data structure.
・The NAX-HEAPIFY procedure, which runs in O(lg n) time, is the key to maintainingthe max-heap property.
・The BUILD-MAX-HEAP procedure, which runs in linear time, produces a max heap from an unordered input array.
・The HEAPSORT procedure, which runs in O(n lg n) time, sorts an array in place.
・The MAX-HEAP-INSERT, HEAP-EXTRACT-MAX, HEAP-INCREASE-KEY and HEAP-MAXIMUM procedures, which run in O(lg n) time, allow the heap data structure to be used as a priority queue.
Maintaining the heap propertyMAX-HEAPIFY is an important subroutine fo rmanipulating max-heap. Its inputs are an array A and an index i into the array. When MAX-HEAPOFY is called, it is assumed that the library trees rooted at LEFT(i) and RIGHT(i) are max-heaps, but that A[i] may be smaller than its children, thus violating the max-heap property. The function of MAX-HEAPIFY is to let the alue at A[i] "float down" in the max-heap so that the sub-tree rooted at index i becomes a mac-heap.
The figures below illustrate the actions of MAX-HEAPIFY. At each step, the largest of the elements A[i], A[LEFT(i)] and A[RIGHT(i)] is determined, and its index is stored in largest. If A[i] is largest, then the subtree rooted at node i is max-heap and the procedure terminates. Otherwise, one of the two children has the largest element, and A[i] is swapped with A[largest]. which causes node i and its children to satisfy the max-heap property. The node indexed by largest, however, now has the original value A[i], and thus the subtree rooted at largest may violate the max-heap property. Consequently, MAX-HEAPIFY must be called recursively on that subtree.



The running time of MAX-HEAPIFY on a subtree of size n rooted at given node is Θ(1) time of fix up the relationships among the elements A[i], A[LEFT(i)], and A[RIGHT(i)], plus the time to run MAX-HEAPIFY on subtree rooted at one of the children of node i. The children's subtrees each have size at most 2n/3 (you can draw a tree to valify this) -- the worst case occurs when the last row of the tree is exactly half full -- and the running time of MAX-HEAPIFY can therefore be descried by the recurrence.
T(n) ≦ T(2n/3) + Θ(1).
The solution to this recurrence, by master theorem or intuitive tree analysis, is T(n) = O(lg n). Alternatively, we can characterize the running time of MAX-HEAPIFY on a node of height h as O(h).
Building a heapWe can use the procedure MAX-HEAPIFY in a button-up manner to convert an array A[1 .. n], where n = length[A], into a maz-heap. The elements in the subarray A(floor[n/2]+1) .. n] are all leaves of the tree, and so each is a 1-element heap to begin with. The procedure BUILD-HEAP goes through the remaining nodes of the tree and runs MAX-HEAPIFY on each one.
Figures below show an example of the action of BUILD-MAX-HEAP.






border="0" />We can computer a simple upper bound on the running time of BUILD-MAX-HEAP as follows. Each call to MAX-HEAPIFY costs O(lg n) time, and there are O(n) such calls. Thus, the running time is O(n lg n). This upper bound, though correct, is not asymptotically tight.
We can derive a tighter bound by observing that the time for MAX-HEAPIFY to run at a node aries with the height of the node in the tree, and the heights of most nodes are small. Our tighter analysis relies on the properties that an n-element heap has height floor[lg n] and at most ceiling[n/2
h+1 nodes of any height h.
The time required by MAX-HEAPIFY when called on a node of height h is O(h), so we can express the total cost of BUILD-MAX-HEAP as being bounded from above by
p135
...
...
O(n).
Hence,
we can build a max-heap from an unordered array in linear time.
The heapsort algorithmThe heapsort algorithm atarts by using BUILD-MAX_HEAP to build a max-heap on the input array A[1 .. n], where n = length[A]. Since the maximum element of the aray is stored at the root A[1], it can be put into its correct final position by exchanging it with A[n] If we now "disvard" node n from the heap, we observe that A[1 .. (n-1)] can easily be made into a max-heap. The children of the root remain max-heaps, but the new root element may violate the max-heap property. All that is needed to restore the max-heap property, however, is one call to MAX-HEAPIFY(A, 1), which leaves a max-heap in A[1 .. (n-1)]. The heapsort algorithm then repeats this process for the max-heap of size n-1 down to a heap of size 2.
#include "heapsort.h"
#include "windows.h"
#include <iostream>
using namespace std;
#define PARENT(i) ((i-1)/2)
#define LEFT(i) ((2*i)+1)
#define RIGHT(i) ((2*i)+2)
void Test::max_heapify(int A[], int i)
{
int l = LEFT(i);
int r = RIGHT(i);
cout<<"l is "<<l<<"r is "<<r<<endl;
int largest;
if (l <= heap_size && A[l] > A[i])
largest = l;
else
largest = i;
if (r <= heap_size && A[r] > A[largest])
largest = r;
cout<<"largest is "<<largest<<endl;
if (largest != i)
{
int tmp = A[i];
A[i] = A[largest];
A[largest] = tmp;
max_heapify(A, largest);
}
}
void Test::build_max_heap(int A[])
{
heap_size = len; // at this phase, active heap size is the length of array A
for (int i=(len-1)/2; i>=0; i--)
{
cout<<"i is "<<i<<endl;
max_heapify(A, i);
}
}
void Test::heapsort(int A[])
{
build_max_heap(A); // build heap only onece
for (int i=len; i>0; i--) // heapify once after every max element extraction
{
int tmp=A[0];
A[0]=A[i];
A[i]=tmp;
heap_size = heap_size-1; // active heap size decreases by 1.
// the rest are the numbers to be sorted.
max_heapify(A, 0);
}
}