您的位置:首页 > 其它

排序算法(2)——堆排序

2017-03-06 00:46 330 查看
[转载] 《算法导论》和 百度百科

1、堆的定义

(二叉)堆是一个数组,它可以被看成一个近似的完全二叉树。树上的每一个节点对应数组中的一个元素。除最底层(叶子层)外其它层都是满的。

规定树的根结点是A[1],这样给定一个节点的下标i,我们可以 很容易计算它的父节点、左孩子、右孩子的下标。

PARENT(i)=i/2;
LEFT(i)=2*i;
RIGHT(i)=2*i+1;


(二叉)堆可分为两种形式:最大堆和最小堆。

最大堆要满足如下性质:

A[PARENT(i)]>=A[i]


即除了根节点以外的所有节点,其父节点的值要大于等于该节点的值。

最小堆是满足如下性质:

A[PARENT(i)]<=A[i]


在从小到大的堆排序中,我们使用最大堆。

2、堆排序的思想

2.1、维护最大堆的性质







2.2、建堆



2.3、堆排序算法







3、堆排序的实现

#include <stdio.h>

//维护最大堆的性质
void HeapAdjust(int array[],int i,int nLength)
{
int nChild;
int nTemp;
for(;2*i+1<nLength;i=nChild)
{
//子结点的位置=2*(父结点位置)+1
nChild=2*i+1;
//得到子结点中较大的结点
if(nChild<nLength-1&&array[nChild+1]>array[nChild])++nChild;
//如果较大的子结点大于父结点那么把较大的子结点往上移动,替换它的父结点
if(array[i]<array[nChild])
{
nTemp=array[i];
array[i]=array[nChild];
array[nChild]=nTemp;
}
else break; //否则退出循环
}
}
//堆排序算法
void HeapSort(int array[],int length)
{
int i;
//建堆
for(i=length/2-1;i>=0;--i)
HeapAdjust(array,i,length);

//堆排序
for(i=length-1;i>0;--i)
{
//把第一个元素和当前的最后一个元素交换,
//保证当前的最后一个位置的元素都是在现在的这个序列之中最大的
array[i]=array[0]^array[i];
array[0]=array[0]^array[i];
array[i]=array[0]^array[i];
//不断缩小调整heap的范围,每一次调整完毕保证第一个元素是当前序列的最大值
HeapAdjust(array,0,i);
}
}
int main()
{
int i;
int num[]={9,8,7,6,5,4,3,2,1,0};
HeapSort(num,sizeof(num)/sizeof(int));
for(i=0;i<sizeof(num)/sizeof(int);i++)
{
printf("%d ",num[i]);
}
printf("\nok\n");
return 0;
}


4、堆排序的性能

建堆时间复杂度是O(n),堆排序是O(nlgn)。所以总的时间复杂度是O(nlgn)。

和其它排序算法的比较:

算法思想类似于选择排序,而且也是不稳定的排序算法。因为简单选择排序每次通过比较找到最大元素,堆排序是通过维护最大堆的性质在根节点找到最大元素,然后放到数组最后,直到所有节点都排好序。既然类似选择排序,那也会影响等值元素在数组中的原有顺序,从而破坏稳定性。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  排序算法 堆排序
相关文章推荐