您的位置:首页 > 其它

堆排序算法原理,实现及时间复杂度分析

2016-09-08 20:30 399 查看
1 堆排序

堆层次:m=log[N]

堆排序其实也是一种选择排序,是一种树形选择排序。只不过直接选择排序中,为了从R[1…n]中选择最大记录,需比较n-1次,然后从R[1…n-2]中选择最大记录需比较n-2次。事实上这n-2次比较中有很多已经在前面的n-1次比较中已经做过,而树形选择排序恰好利用树形的特点保存了部分前面的比较结果,因此可以减少比较次数。对于n个关键字序列,最坏情况下每个节点需比较log2(n)次,因此其最坏情况下时间复杂度为nlogn。堆排序为不稳定排序,不适合记录较少的排序。

#include<iostream>
using namespace std;

int rcount=0;
int scount=0;
int successchange=1;

void output(int *a,int size){
for(int i=1;i<=size;i++){
cout<<a[i]<<' ';
}
cout<<endl;
}

bool judge(int i,int size){//judge if is a leaf node
return i<=size/2;
}

bool hasRightChild(int i,int size){
return 2*i+1<=size;
}

bool swap(int *a,int i,int size,int*which){//which means which child is changed
scount++;
int q=a[i];
if(hasRightChild(i,size)){
if(q>=a[2*i]&&q>=a[2*i+1])return false;
if(a[2*i]>a[2*i+1]){
a[i]=a[2*i];a[2*i]=q;*which=2*i;
}else{
a[i]=a[2*i+1];a[2*i+1]=q;*which=2*i+1;
}
return true;
}else{
if(q>=a[2*i])return false;
a[i]=a[2*i];a[2*i]=q;*which=2*i;return true;
}
}

void p(int*a,int i,int size,int time){//time means which time to adjust
rcount++;
int which=-1;
if(judge(i,size)){
//i maybe just has one left child
if(a[i]>=a[2*i]&&a[i]>=a[2*i+1]&&time!=0)return;
if(hasRightChild(i,size)&&judge(2*i+1,size)){//not leaf node
if(time==0){
p(a,2*i+1,size,time);
}else if(a[i]<a[2*i+1]){
p(a,2*i+1,size,time);
}
}
if(time==0){
if(judge(2*i,size))p(a,2*i,size,time);//not leaf node
}else if(a[i]<a[2*i]){
if(judge(2*i,size))p(a,2*i,size,time);//not leaf node
}
if(swap(a,i,size,&which))p(a,which,size,time);//p(a,i,size);
}else{
if(i%2==1&&!(size==1&&i==1)){//(size==1&&i==1) used to limit overflow
if(ti
dc57
me==0){
if(judge(i-1,size))p(a,i-1,size,time);//not a leaf node
if(swap(a,(i-1)/2,size,&which))p(a,which,size,time);
}else if(a[(i-1)/2]<a[i-1]){
if(judge(i-1,size))p(a,i-1,size,time);//noe a leaf node
if(swap(a,(i-1)/2,size,&which))p(a,which,size,time);
}
}
}
}

void workout(int *a,int size){
if(size==1)return;
int n=size;
int tmp=0;

for(int i=0;i<n;i++,size--){
successchange=0;
p(a,1,size,size!=n);
tmp=a[size];a[size]=a[1];a[1]=tmp;
//        cout<<"this is loop "<<i<<":";
//        output(a,n);
}
}

int main(int argc,char**argv){

//int a[]={-1,16,7,3,20,17,8};
//int size=6;

//int a[]={-1,2,2,4,9,3,6,7,1,5};
//int size=9;

//int a[]={0,10,9,8,7,6,5,4,3,2,1};
//int size=10;

//int a[]={0,1,2,3,4,5,6,7,8,9,10};
//int size=10;

//int a[]={0,10,9};
//int size=2;

int a[101];
for(int i=1;i<101;i++)a[i]=100-i;
int size=100;

cout<<"origin is:\t";output(a,size);
workout(a,size);
cout<<"after sort:\t";output(a,size);
cout<<"recurve call count:"<<rcount<<endl;
cout<<"swap call count:"<<scount<<endl;

return 0;
}


运行结果如下:



别人的堆排序实现算法:

/*堆排序(大顶堆) 2011.9.14*/

#include <iostream>
#include<algorithm>
using namespace std;

int rcount=0;
int scount=0;

void HeapAdjust(int *a,int i,int size)  //调整堆
{
rcount++;
int lchild=2*i;       //i的左孩子节点序号
int rchild=2*i+1;     //i的右孩子节点序号
int max=i;            //临时变量
if(i<=size/2)          //如果i不是叶节点就进行调整
{
if(lchild<=size&&a[lchild]>a[max])
{
max=lchild;
}
if(rchild<=size&&a[rchild]>a[max])
{
max=rchild;
}
if(max!=i)
{
swap(a[i],a[max]);scount++;
HeapAdjust(a,max,size);    //避免调整之后以max为父节点的子树不是堆
}
}
}

void BuildHeap(int *a,int size)    //建立堆
{
int i;
for(i=size/2;i>=1;i--)    //非叶节点最大序号值为size/2
{
HeapAdjust(a,i,size);
}
}

void HeapSort(int *a,int size)    //堆排序
{
int i;
BuildHeap(a,size);
for(i=size;i>=1;i--)
{
//cout<<a[1]<<" ";
swap(a[1],a[i]);           //交换堆顶和最后一个元素,即每次将剩余元素中的最大者放到最后面
//BuildHeap(a,i-1);        //将余下元素重新建立为大顶堆
HeapAdjust(a,1,i-1);      //重新调整堆顶节点成为大顶堆
}
}

int main(int argc, char *argv[])
{
//int a[]={0,16,20,3,11,17,8};
int a[101];
int size=100;
for(int i=1;i<=100;i++)a[i]=100-i;
HeapSort(a,size);
for(int i=1;i<=size;i++)
cout<<a[i]<<" ";
cout<<endl;

cout<<"recurve count is:"<<rcount<<endl;
cout<<"swap count is:"<<scount<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  堆排序 算法
相关文章推荐