堆排序是一种树形选择排序,在排序过程中,将数组a[]看成一棵完全二叉树,利用双亲节点和孩子节点之间的内在关系,在当前无序的序列中选择关键字最大(或最小)的排序。其空间复杂度为O(1),在最坏的情况下时间复杂度为O(nlog2n)。堆排序是一种不稳定的算法,且只能用于顺序结构,不能用于链式结构;初始建堆所需的比较次数较多,因此记录少的时候不宜采用。堆排序在最坏情况下的时间复杂度比快速排序下最坏的时间复杂度O(n2)更为优秀,当记录比较多的时候较为高效。
下面实现代码:
首先是预定义和类型定义:
#define OK 1
#define ERROR 0
typedef int Status;
typedef int ElemType;
typedef struct{
ElemType *data;
int length;
}SqList;
顺序表的插入:
Status EnSqList(SqList *L,ElemType e,int n)
{
if (L->length > n)
return ERROR;
L->data[L->length + 1] = e;
L->length++;
return OK;
}
筛选法调整堆:
void HeapAdjust(SqList *L, int s, int m)
{
int j;
ElemType rc;
rc = L->data[s];
for (j = 2 * s; j <= m; j *= 2)
{
if (j < m&&L->data[j] < L->data[j + 1])
j++;
if (rc>=L->data[j])
break;
L->data[s] = L->data[j];
s = j;
}
L->data[s] = rc;
}
声明rc用于储存下标为s的元素的值。初始化j为2*s,使j指向s的左子树,当j小于或等于最大上限m的时候,执行循环:如果j小于m并且下标为j的元素小于其后一个元素时,让j加1使j指向下一个元素,即在s的左右子树总选取最大值并在j中记录其下标;如果左右子树中最大值小于rc的值,则跳出循环,此时s指向rc应该储存的位置,即其双亲节点大于rc,其左右子树节点均小于rc;若左右子树中最大值大于rc的值,则让其子树节点j的值赋值给双亲节点s,然后让s指向其子树节点j。
跳出循环后让rc的值赋值给下标为s的节点。
建初堆:
void CreatHeap(SqList *L)
{
int i;
for (i = L->length / 2; i >= 1; i--)
HeapAdjust(L, i, L->length);
}
从最后一个节点的双亲节点开始,逐步调用HeapAdjust()以创建大根堆,以确保以i为双亲节点的树是大根堆(从图上来看,是从底层到顶层创建大根堆的做法)。
堆排序算法的实现:
void HeapSort(SqList *L)
{
int i;
ElemType x;
CreatHeap(L);
for (i = L->length; i > 1; --i)
{
x = L->data[1];
L->data[1] = L->data[i];
L->data[i] = x;
HeapAdjust(L, 1, i - 1);
}
}
先引用CreatHeap()函数对数组进行排序,使其成为大根堆,而后,交换下标为1和最后一个元素(即下标i元素)的值,因为堆排序的结果得到的是一个小根堆,并且在数组中呈递增,,而此时下标为1的元素保存着最大元素的值,而最后一个元素(下标为i的元素)保存着最小元素的值,故将其对调后,最后一个元素(下标为i的元素)保存的必然是最大元素,已经达到目的位置,让i减一(往前移动一位),令原来i的前一位为最后一个数据继续进行堆排序(类似于将未排序完成的元素作为一个数组,排序完成的元素作为一个数组,排序时不对已经排序完成的数组进行操作,仅仅对未排序的数组进行堆排序,结束的时候将最后一位,即排序归并到排序完成的数组中)。
加入main()函数:
int main(void)
{
SqList L;
ElemType e;
int i, n;
L.length = 0;
printf("输入元素个数:");
scanf("%d", &n);
L.data = (int *)malloc(sizeof(int)*n);
srand((int)time(0));
for (i = 0; i < n; i++)
{
e = rand();
EnSqList(&L, e, n);
}
printf("排序前数组:");
for (i = 0; i < L.length; i++)
printf("%d ", L.data[i + 1]);
printf("\n");
HeapSort(&L);
printf("排序后数组:");
for (i = 0; i < L.length; i++)
printf("%d ", L.data[i + 1]);
printf("\n");
return 0;
}