由于树形选择排序具有辅助存储空间多、进行多余比较等缺点,因此经常被堆排序替代。
本文针对堆排序。
首先认识什么是堆:
n个元素的序列Kl、K2、……… 、Kn满足如下性质时称为堆:
ki <= k(2i),ki <= k(2i+1),其中(1≤i≤ n),时是小根堆。
ki >= k(2i),ki >= k(2i+1),其中(1≤i≤ n),时是大根堆。
怎么理解呢?如果把该数组看作是完全二叉树,那么小根堆就是非终端节点的值都小于其左右子节点的值,所以小根堆的父节点的值最小,而大根堆就是非终端节点的值都大于其左右子节点的值,所以大根堆的父节点的值最大。
大根堆排序的思想是:
1. 将数组a[1..n]整理成一个大根堆,构成一个最大的无序区域
2. 从下标大到小做排序,每次将当前无序区的堆顶记录a[1]和该区间的最后一个记录交换,然后将新的无序区调整为堆。
程序:
程序中22应该是2,源代码是2,但是csdn却总显示22.
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define MAXSIZE 50
#define N 15
typedef struct{
int key;
int other;
}node;
typedef struct
{
node array[MAXSIZE + 1];
int length;
}list;
/*调整array[min--max]为大顶堆*/
void heap_adjust(list *l,int min,int max)
{
node rc;
int i;
rc = l->array[min];
for(i = 2 * min;i <= max;i *= 2){
if(i < max && l->array[i].key < l->array[i+1].key) /* i为左右子节点中较大的值的下标 */
++i;
if(rc.key > l->array[i].key)
break;
l->array[min] = l->array[i]; /* 互换min、i位置的内容 */
min = i;
}
l->array[min] = rc;
}
/*堆排序*/
void heap_sort(list *l)
{
node t;
int i;
for(i = l->length/2;i > 0;--i) /* 把H.array[1--length]建成大顶堆 */
heap_adjust(l,i,l->length);
for(i = l->length;i > 1;--i){
t = l->array[1]; /*互换堆顶元素和当前未排序子序列H.array[1--i]中最后一个记录的值*/
l->array[1] = l->array[i];
l->array[i] = t;
heap_adjust(l,1,i - 1); /*调整array[1--i-1]为大顶堆*/
}
}
/*打印序列*/
void print(list *l)
{
int i;
for(i = 1;i <= l->length;i++)
printf("%d %d\t",l->array[i].key,l->array[i].other);
printf("\n");
}
void main()
{
node data[N]={{5,6},{13,5},{22,2},{2,4},{6,5},{99,7},{6,15},{1,22},{15,12},{58,12},{48,40},{26,48},{38,35},{72,58},{61,22}};
list l;
int i;
for(i = 0;i < N;i++)
l.array[i + 1] = data[i];
l.length = N;
printf("befor sort:\n");
print(&l);
heap_sort(&l);
printf("after heap sort:\n");
print(&l);
getch();
}
结果: