这次我来介绍排序算法中的堆排序。
说到堆排序我就想多说几句,在我认为堆排序在所有排序算法中是比较复杂·的一种排序算法,所以我推荐一般情况下不要用这种排序算法。
废话不多说,下面我就来说一下堆排序。
堆排序是一种树形选择排序,在排序过程中,将待排序的记录看成 一颗完全二叉树的顺序存储结构,利用完全二叉树中双亲节点和孩子节点之间的内在关系,在当前无序的序列中选择关键字最大(或最小)的记录。
提到堆了,我再来介绍一下什么是堆。
二叉树中双亲节点永远大于孩子节点(或双亲节点永远小于孩子节点)就被成为堆。
堆排序的步骤大致是先把待排序序列构建成二叉树,然后再把该二叉树经过排序变成堆,然后再把堆顶的元素与堆的最后位置的元素进行交换,重复上述过程直至最后一个元素。
下面我就以序列(49,38,65,97,76,13,27,49)为例来详细介绍一下堆排序
实现堆排序需要解决两个问题堆排序算法才能算完成,问题如下
1、建初堆:将一个无序序列建成一个有序序列
2、调整堆:将堆顶元素与堆底元素进行交换,在堆顶元素改变后,调整剩余元素成为一个新的堆。
对以上两个问题的代码如下
//建初堆
void CreatHeap(int *str){//把无序列建成大根堆
int n;//记录待排序序列的长度
n=sizeof(str)/4; //纪录序列的长度
for(int i=n/2-1;i>=0;i--){ //把子树变成大根堆
HeapAdjust(str,i,n-1);
}
}
//调整堆
void HeapAdjust(int *str,int t,int n){ //把二叉树变成大根堆
int fa,son,x;//fa表示双亲节点,son表示儿子节点
fa=t;
son=2*fa+1;
while(son<=n){ //把子树的值进行位置调换变成大根堆
if(son+1<=n&&str[son]<str[son+1])
son++;
if(str[fa]<str[son]){
x=str[fa];
str[fa]=str[son];
str[son]=x;
}
else
break;
fa=son; //进行下一个子树变成大根堆的过程
son=2*fa+1;
}
}
void HeapSort(int *str){ //对序列进行排队
int n,x;
n=sizeof(str)/4;
for(int i=n-1;i>=0;i--){ //交换堆顶与堆底的值进行排序
x=str[0];
str[0]=str[i];
str[i]=x;
HeapAdjust(str,0,i)
}
}
堆排序算法的特点
1、不稳定排序
2、只能用于顺序结构,不能用于链式结构
3、初始建堆所需的比较次数较多,因此记录数较少时不宜采用。堆排序在最坏情况下时间复杂度为O(nlog2n),相对于快速排序最坏情况下的O(n^2)而言更有优势,当记录较多时较为高效。
堆排序虽然比较复杂,但是多看看和练习一下就没什么问题了,希望大家多多指教。