堆排序

5.3.3.堆排序

堆:设有数据元素的集合(R1,R2,R3,...Rn)它们是一棵顺序二叉树的结点且有

       Ri<=R2i 和Ri<=R2i+1(或>=)

堆的性质:堆的根结点上的元素是堆中的最小元素,且堆的每一条路径上的元素都是有序的。

堆排序的思想是:

1)heapdown调整堆:每次调整都是从父节点、左孩子节点、右孩子节点三者中选择最大者跟父节点进行交换(交换之后可能造成被交换的孩子节点不满足堆的性质,因此每次交换之后要重新对被交换的孩子节点进行调整)

2)heapbuild建初始堆(将结点[n/2],[ n/2]-1,...3,2,1分别调成堆)

3)heapsort

     建立初始堆,

       当未排序完时

         输出堆顶元素,删除堆顶元素,将剩余的元素重新建堆。

         方法:将堆顶元素与最后无序元素交换,调整堆顶元素。

  

堆排序:稳定的nlog(n),只需要一个临时空间。

每次可以在log(n)的时间复杂度内求无序数据的最值。应用在优先队列内。

 

例题:3110 二叉堆练习3

题目描述 Description

给定N(N≤500,000)和N个整数(较有序),将其排序后输出。

输入描述 Input Description

N和N个整数

输出描述 Output Description

N个整数(升序)

样例输入 Sample Input

5

12 11 10 8 9

样例输出 Sample Output

8 9 10 11 12

数据范围及提示 Data Size & Hint

对于33%的数据 N≤10000

对于另外33%的数据 N≤100,000  0≤每个数≤1000

对于100%的数据 N≤500,000  0≤每个数≤2*10^9

 

程序如下:

从小到大排序,建立大顶堆。

写法一:数组做全局变量

#include<stdio.h>

#include<iostream>

#include<stdlib.h>

using namespace std;

int n,len,a[500009];

void heapdown(int i){每次向下调整堆顶元素

       int j;

       j=2*i;

       while(j<=n){ //可能多次进行,所以while语句调整

              if(j<n&&a[j]<a[j+1])j++;

              if (a[i]<a[j])swap(a[i],a[j]);

              i=j;

              j=2*i;

       }

}

void heapbuild(){//建立初始堆

    int i;

       for(i=n/2;i>0;i--)heapdown(i);

}

void heapsort(){//堆排序

       int i;

       heapbuild();      //建立初始堆,堆顶元素最大

       while(n>=2){

              swap(a[1],a[n]);//将堆顶元素与最后无序元素交换

              n--;//无序长度不断缩短

              heapdown(1);   //堆顶元素可能是个较小的数,向下调整

       }

      

}

int main(){

       scanf("%d",&n);

       int i;

       len=n;

       for(i=1;i<=len;i++)

         scanf("%d",&a[i]);

       heapsort(); 

       for(i=1;i<=len;i++)

         printf("%d ",a[i]);

}

 

如果要进行多组数的堆排序,需要传递数组参数

写法二:数组作为参数传递。

#include<stdio.h>

#include<iostream>

#include<stdlib.h>

using namespace std;

int n,len,b[500009];

void heapdown(int a[],int i,int size){

       int j;

       j=2*i;

       while(j<=size){

              if(j<size&&a[j]<a[j+1])j++;

              if (a[i]<a[j])swap(a[i],a[j]);

              i=j;

              j=2*i;

       }

}

void heapbuild(int a[],int size){

    int i;

       for(i=size/2;i>0;i--)heapdown(a,i,size);

}

void heapsort(int a[],int size){

       int i;

       heapbuild(a,size);   

       while(size>=2){

              swap(a[1],a[size]);

              size--;

              heapdown(a,1,size);      

       }

      

}

int main(){

       scanf("%d",&n);

       int i;

       len=n;

       for(i=1;i<=len;i++)

         scanf("%d",&b[i]);

       heapsort(b,len); 

       for(i=1;i<=len;i++)

         printf("%d ",b[i]);

}

转载于:https://www.cnblogs.com/FuTaimeng/p/5603892.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值