您的位置:首页 > 其它

堆排序

2015-08-22 14:05 218 查看
堆排序用到的是完全二叉树的性质,所以在看这篇文章之前先学习完全二叉树。
http://baike.baidu.com/link?url=HUZLyRNtNhAUzf7rgffW3IHkPbNQF_0vO63EvTKZBgYztrMz02B2_-PlCV5eFg6J8y8w8sHEu4Bd7bZVOXozaK
那么,学会了完全二叉树,现在就可以学习堆排序了。

个人认为,堆排序是插入排序和快排思想的联合,所以读者可以先学会插入排序和快排。

  插入排序:每次选出带排序序列的最大值,加入已排好序的序列;

  快排:在待排序序列中选择一个记录,让它左边的都比它小,右边的都比它大,如此递归。

思考:

对于插入排序,时间复杂度主要在选择最大值的过程中。有没有一种方法可以用更少的时间就选出最大值呢?

对于快速排序,如果用完全二叉树存储,让根节点比左子树大,比右子树也大,那这个根节点不就是最大值吗?

两相结合,堆排序应运而生,而核心就是完全二叉树的性质。下面可以看看堆排序相关的概念,有助于理解。
http://baike.baidu.com/link?url=Fc3__n67naxdKu_l7MzWi6WCn4QbbJESFSKiJUvvO-CzszGyoqv0coneADUg6DjcJEAVpymvhqwm8qRe9gEYSK
下面是堆排序的代码:

#include<stdio.h>
void creatheap(int *a,int n,int i)  //整理堆的函数,包括三个参数,数组首地址,数组元素个数,要处理的结点编号
{
if (i*2+1>n)   //如果 这个结点没有右孩子
{
if (i*2>n) return;  //如果再没有左孩子,直接return
else    //如果有左孩子,就比较这个结点和左孩子是否需要交换
{
if (a[i*2]>a[i])
{
a[0]=a[i];
a[i]=a[i*2];
a[i*2]=a[0];
creatheap(a,n,2*i);  //递归左孩子
}
else return;  //不需要交换的话直接return
}
}
else //如果有右孩子(那么肯定有左孩子啦~)
{
if (a[i*2+1]<=a[i]&&a[i*2]<=a[i]) return; //经过比较左右孩子都不需要交换,说明这个堆不用处理了,return
else{  //否则,这个堆需要处理
int maxi=i*2;  //下面分析需要处理左孩子还是右孩子
if (a[i*2+1]>a[i*2]) maxi++;
a[0]=a[i];
a[i]=a[maxi];
a[maxi]=a[0];
creatheap(a,n,maxi);  //递归需要处理的那个
}
}  //这样就完成了一次整理
}
int main()
{
int b[101]={0};
int n;
scanf("%d",&n);
int i;
for (i=1;i<=n;i++)
{
scanf("%d",b+i);
}
for (i=n/2;i>=1;i--)  //对非叶子结点递减整理,n/2是第一个非叶子结点的编号
{
creatheap(b,n,i);
}
//这样整理完之后目前这个数组是一个堆了 可以确定的是第一个元素b[1]一定是最值
int k=n;
while (n!=1)
{
b[0]=b[1];
b[1]=b
;
b
=b[0];
n--;
creatheap(b,n,1);  //把b[1]移到末尾,然后同理整理前n-1个元素,直到n=1
}
for (i=1;i<=k;i++)  //堆排序完成
{
printf("%d ",b[i]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: