堆可以看作是一个完全二叉树,分为大顶堆和小顶堆,本文我们以大顶堆为例来实现堆排序。
(1)建堆
先把给定的序列转换成一棵完全二叉树,然后逐步对其调整使其每个结点的值都大于其两个子结点的值,因此我们需要从第一个非叶结点开始逐步向前调整(叶结点不存在子结点比其大的状况,所以从非叶结点往前调整),假设一共有n个元素,那么第一个调整的结点为n/2。
(2)交换并调整
每次调整后将第一个最大的结点跟尾结点换位,则每一轮都是最大的在末尾,然后再次堆第一个结点进行调整,使得成为大顶堆,然后再次交换并调整,以此往复。
void shift(int a[], int low, int high){ //对数组中处于low位的结点进行一次向下调整 int temp = a[low]; int i = low, j = 2*i; //i为待调整结点,j为i的子结点, while(j <= high){ //若i没有子结点则跳出循环 if(a[j] < a[j+1]) //跟子结点中较大的比较 j++; if(a[j] > temp){ //大顶堆子结点较大就跟双亲结点换位 a[i] = a[j]; i = j; j = 2 * i; } else break; } a[i] = temp; }
void heapSort(int a[], int n){ //数组下标从1开始 int i; int temp; for (i = n/2; i >= 1; --i) //建堆,从第一个非页结点即n/2开始逐步往前调整 { shift(a, i, n); } for (i = n; i >= 2; ++i)//调整的第二个结点就行了,后面n-1个结点有序,且较大 { tmep = a[1];//每次调整后将第一个最大的跟尾结点换位,则每一轮都是最大的在末尾 a[1] = a[i]; a[i] = temp; shift(a, 1, n-1); } }