您的位置:首页 > 理论基础 > 数据结构算法

C++代码,数据结构-内部排序-选择排序-堆排序

2014-03-14 21:35 447 查看
最简单的选择排序,的时间复杂度为N2;其主要操作就是比较,从减少次数出发来改进算法,书上提到了树形选择排序,但是有需要的辅助空间较多等缺点,为了弥补,威洛姆斯提出了另一种形式的选择排序——堆排序,

根据堆的定义,我们可以把一个序列对应的一维数组看成是一个完全二叉树,堆顶为最大值或者最小值,也就是完全二叉树的根,。

堆排序我看了好久,最主要的原因就是对完全二叉树的性质掌握不深,

若根的起点标号从0开始。

则一个结点i,它的双亲结点的标号为(i-1)/2 ,他左孩子的标号是(i*2+1),它右孩子的标号是(i*2+2).

若根的起点标号从1开始,

则一个结点i,它的双亲结点的标号为 i/2 ,他左孩子的标号是i*2,它右孩子的标号是i*2+1

不管怎么说,又发现一种神奇结构,堆

直接上代码了:

#include<iostream>
#include<cstdlib>
#include<fstream>
#include<cstdlib>
#include<ctime>
using namespace std;
//第十章 内部排序
//选择排序-堆排序
//待排记录数据的数据结构
#define maxsize 100000
struct redtype{
int key;
};
struct Sqlist
{
redtype r[maxsize];
int length;
};

int buildsq(Sqlist &sq){
int x;
cin>>x;
sq.length=x+1;
for(int i=1;i<=x;++i)
{int p;
cin>>p;
sq.r[i].key=p;
}
return x;
}

void Headadjust(Sqlist &sq,int s,int m){//调整s到序列最后位置m的元素
int rc=sq.r[s].key;//记录下当前需要调整的关键字
for(int j=2*s;j<=m;j*=2){//先左孩子跟右孩子比较,s的左孩子就是2*s,,而且沿着key较大的孩子结点向下涮选
if(j<m&&sq.r[j].key<sq.r[j+1].key) {++j;}//我做的是最大堆,所以 j为key较大的记录的标号
    if(rc>sq.r[j].key) {break;}//当前关键字大于key较大的了,不用调整
    sq.r[s].key=sq.r[j].key;s=j;//需要调整,s位置赋值较大的,
}
sq.r[s].key=rc;//插入
}

void Heapsort(Sqlist &sq){//算法10.11
//先堆化一个数组。
for(int j=(sq.length-1)/2;j>0;--j){//对于叶子节点来说,可以认为它已经是一个合法的堆了,只需要从最后一个非终端结点开始调整
Headadjust(sq, j ,sq.length-1);//注:最后一个非终端结点的标号是关键字个数/2,
}

for(int i=sq.length-1;i>1;--i){//依次取出堆顶,最大值放在length-1位置,
    int tem=sq.r[1].key;//记录堆顶元素
    sq.r[1].key=sq.r[i].key;//把i位置上的元素放入堆顶
    sq.r[i].key=tem;//i位置上放入堆顶元素
    Headadjust(sq,1,i-1);//1 到 i-1 重新调整 
}

}

int main(){

    Sqlist sq;
 int t= buildsq(sq);

Heapsort(sq);

for(int i=1;i<=t;++i){

    cout<<sq.r[i].key<<" ";
}

return 0;
}
有个小疑问,为什么完全二叉树的最后一个非终端结点是N/2
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐