堆排序
基本思想:在排序过程中,将数据看成一棵完全二叉树,利用完全二叉树中双亲结点和子结点的关系来选择关键值最小的记录。
堆的定义:n个元素序列h1, h2, …, hn,当hi>=h2i, h2i+1时,或当hi<=h2i, h2i+1时,称为堆;前者称为大根堆,后者称为小根堆。
以完全二叉树表示堆,以数组r[0…n-1]存储堆。
堆调整:
若结点i的左、右子树均为堆,将r[i]与r[2i+1]和r[2i+2]比较,若不满足堆的条件,将r[2i+1]和r[2i+2]中的大者与r[i]交换;
依次向下层执行(1),直到所有子树均为堆为止。
建堆:对于任意一个以完全二叉树表示的堆,从i=[n/2]-1开始到0,反复调用堆调整。
堆排序:
(1)建堆;
(2)交换堆的根与未排序的最后一个叶子,该叶子进入已排序序列中;
(3)对未排序二叉树进行堆调整;
(4)重复步骤(2)和(3),直至未排序二叉树为空。
参考代码:(参考《大话数据结构》)
/* 交换L中数组r的下标为i和j的值 */
void swap(SqList *L,int i,int j)
{
int temp=L->r[i];
L->r[i]=L->r[j];
L->r[j]=temp;
}
void HeapAdjust(SqList *L,int s,int m)
{
int temp,j;
temp=L->r[s];
for(j=2*s;j<=m;j*=2) /* 沿关键字较大的孩子结点向下筛选 */
{
if(j<m && L->r[j]<L->r[j+1])
++j; /* j为关键字中较大的记录的下标 */
if(temp>=L->r[j])
break; /* rc应插入在位置s上 */
L->r[s]=L->r[j];
s=j;
}
L->r[s]=temp; /* 插入 */
}
/* 对顺序表L进行堆排序 */
void HeapSort(SqList *L)
{
int i;
for(i=L->length/2;i>0;i--) /* 把L中的r构建成一个大根堆 */
HeapAdjust(L,i,L->length);
for(i=L->length;i>1;i--)
{
swap(L,1,i); /* 将堆顶记录和当前未经排序子序列的最后一个记录交换 */
HeapAdjust(L,1,i-1); /* 将L->r[1..i-1]重新调整为大根堆 */
}
}