您的位置:首页 > 其它

排序算法之堆排序

2016-04-13 22:01 337 查看
介绍堆排序算法之前必须知道“堆”这种数据结构,堆可近似看成是一个完全二叉树,不同的是用数组中的元素从上到下,从左到右填充该树。

堆可分为最大堆和最小堆(查看定义),堆排序算法就是建立在最大堆或者最小堆基础上,通过不断取出堆顶元素,将剩下n-1个元素重新建堆,如此循环获得有序序列。所以关键在于如何建最大堆/最小堆和如何调整剩余元素为新堆。(不上图了,大家看其他博客)

堆排序用在大数据量比较有效,同时不仅用于排序,推广到取最值的引用中,例如进程调度:选取优先级最高的进程,时间调度中:取执行时间最短或者等待时间最长等等。

1.堆的存储

堆一般以数组的形式表示,i节点的父节点是(i-1)/2,子节点是2*i +1和2*i+2,例如节点0的子节点是1和2。

2.堆的操作

堆操作包括堆的插入(插入堆尾),删除及删除后调整(删除堆顶,重新调整)。堆排序是建堆后取得堆顶元素,所以,重点对删除及删除后调整进行操作。

建堆用到递归思想,堆的调整是自下往上,把i节点和它的两个子节点2*i+1和2*i+2进行比较,找出最大的节点存到i节点中,i从树的最后一个非叶子节点开始往上取,每一趟便找出最大值,如此往复。

3.实现:(VC6.0验证通过)

#include<stdio.h>

//i节点及2*i+1与2*i+2三节点找出最大值,i==start
void Adjust(int a[],int start,int len)
{
int i,max,tmp;
i=start;
max=i;
while((2*i+1)<len || (2*i+2)<len)//循环使子树都为堆
{
if((2*i+1)<len && a[2*i+1]>a[i])
max=2*i+1;
//右子节点存在的话,左子节点一定存在,所以与前两个的最大值比
if((2*i+2)<len && a[2*i+2]>a[max])

max=2*i+2;
/*****选取三个数中的最大值***************
if((2*i+1)<len && (2*i+2)<len)
{
if (a[2*i+2]<a[2*i+1])
max=2*i+1;
else
max=2*i+2;
}//有bug,如果只有一个子节点呢
**************************************/
if(a[max]>a[i])
{
tmp=a[max];
a[max]=a[i];
a[i]=tmp;
i=max;
}
else
break;
}
}

void Build(int a[],int len)//从下往上构造最大树
{
int i;
for(i=len/2-1;i>=0;i--)//len/2-1为最后一个非叶子结点
{
Adjust(a,i,len);
}
}

void Heapsort(int a[],int len)//将数的根节点与尾节点交换后,重新构造树
{
int i,tmp;
Build(a,len);
for(i=len-1;i>=0;i--)
{
tmp=a[i];
a[i]=a[0];
a[0]=tmp;//交换第一个值与最后一个值
Adjust(a,0,i-1);//重新调整剩下的n-1个数
}
}
//打印数组
print(int a[],int len)
{
int i;
for(i=0;i<len;i++)
printf("%d ",a[i]);
printf("\n");
}

void main()
{
int a[]={5,3,4,2,6,8,1,7};
print(a,8);
Heapsort(a,8);
print(a,8);
}


后续总结:堆排序首先建造堆(从下往上),取堆顶元素后,调整堆(从上往下)。建造堆时,从最后一个非叶子节点开始,与子节点比较,将最大值存储到i节点中,以此往上,构造出最大堆;将堆顶元素与堆尾元素交换后,对余下元素(除最大元素)用同样方法调整,建造新的堆…
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: