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(time==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;
}