堆排序(C++实现)

堆有最大堆和最小堆之分,最大堆就是每个节点的值都>=其左右孩子(如果有的话)值的完全二叉树。最小堆便是每个节点的值都<=其左右孩子值的完全二叉树。 

堆操作的相关链接http://www.java3z.com/cwbwebhome/article/article1/1362.html?id=4745

堆的定义如下:n个元素的序列{k1,k2,...,kn}当且仅当满足下列关系时,称之为堆。

Ki≤K2i 且Ki≤K2i+1(小顶堆)

或者 K≥K2i 且KiK2i+1(大顶堆)

若将和次序列对应的一维数组看成一个完全二叉树,则堆的含义表明,完全二叉树所有非终端结点的值均不大于(或不小于)左右孩子结点的值。由此,若序列{k1,k2,...,kn}是堆,则堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或者最大值)。

若在输出堆顶的最小值后,使得剩余的n-1个元素的序列重新建一个堆,则得到n个元素中的次小值。如此反复执行,便得到一个有序序列,这个过程称之为堆排序。

实现堆排序需要解决两个问题:

(1) 如何又一个无序序列建成一个堆

从最后一个非终端结点开始筛选,是第n/2个元素

(2)如何在输出堆顶元素后,调整剩余元素成为一个新的堆

只有第一个元素(或根节点)不符合堆的定义

堆排序的算法,示例代码:

#include<iostream>
using namespace std;


维护最大堆的性质,非递归方法
//void max_heapify(int *A,int i,int heap_size){
//<span style="white-space:pre">	</span>int j=2*i;
//<span style="white-space:pre">	</span>for(;j<=heap_size;j*=2){
//<span style="white-space:pre">		</span>if(j<heap_size&&A[j]<A[j+1]) //找出左右孩子中值最大的孩子下标
//<span style="white-space:pre">			</span>j++;
//<span style="white-space:pre">		</span>if(A[i]>=A[j]) //无需调整,直接退出
//<span style="white-space:pre">			</span>break;
//<span style="white-space:pre">		</span>int temp=A[i];//交换数据
//<span style="white-space:pre">		</span>A[i]=A[j];
//<span style="white-space:pre">		</span>A[j]=temp;<span style="white-space:pre">		</span>
//<span style="white-space:pre">		</span>i=j; //继续调整发生数据交换的A[i]
//<span style="white-space:pre">	</span>}
//<span style="white-space:pre">	</span>
//}


//维护最大堆的性质,时间复杂度为O(logN)
void max_heapify(int *A,int i,int heap_size){
<span style="white-space:pre">	</span>int lnode = 2*i;
<span style="white-space:pre">	</span>int rnode = 2*i+1;
<span style="white-space:pre">	</span>int largest=i;//默认i为最大值下标
<span style="white-space:pre">	</span>if( lnode <= heap_size && A[lnode] > A[largest])//如果A[i]为叶子结点,则满足结束递归条件(lnode>heap_size)
<span style="white-space:pre">		</span>largest=lnode;
<span style="white-space:pre">	</span>if(<span style="white-space:pre">	</span>rnode <= heap_size && A[rnode] > A[largest])
<span style="white-space:pre">		</span>largest=rnode;
<span style="white-space:pre">	</span>if(largest!=i){      //需要维护堆的性质
<span style="white-space:pre">		</span>int temp=A[i];
<span style="white-space:pre">		</span>A[i]=A[largest];
<span style="white-space:pre">		</span>A[largest]=temp;
<span style="white-space:pre">		</span>max_heapify(A,largest,heap_size);
<span style="white-space:pre">	</span>}


}


//构建一个最大堆,时间复杂度为O(N)
void build_max_heap(int *A,int A_length){ 
<span style="white-space:pre">	</span>int heap_size=A_length;
<span style="white-space:pre">	</span>for(int i=heap_size/2;i>=1;i--){ //第一个非叶子结点开始进行,构造一个最大堆
<span style="white-space:pre">		</span>max_heapify(A,i,heap_size);
<span style="white-space:pre">	</span>}
}


//堆排序,时间复杂度度为O(NlogN)
void heapsort(int *A,int A_length){
<span style="white-space:pre">	</span>build_max_heap(A,A_length);
<span style="white-space:pre">	</span>int heap_size=A_length;
<span style="white-space:pre">	</span>while(heap_size>=2){
<span style="white-space:pre">		</span>int temp=A[1];
<span style="white-space:pre">		</span>A[1]=A[heap_size];
<span style="white-space:pre">		</span>A[heap_size]=temp;
<span style="white-space:pre">		</span>--heap_size;//堆的长度减少1
<span style="white-space:pre">		</span>if(heap_size>1)
<span style="white-space:pre">			</span>max_heapify(A,1,heap_size);  //此时,只有A[1]可能不符合最大堆性质
<span style="white-space:pre">	</span>}
}




int main(){
<span style="white-space:pre">	</span>int A[11]={0,4,1,3,2,9,9,10,14,2,7};//为了下标从1开始,A[0]存储的不是有效数据 ,有效数据从A[1]开始
<span style="white-space:pre">	</span>cout<<"A 排序前: ";
<span style="white-space:pre">	</span>for(int i=1;i<=10;i++)
<span style="white-space:pre">		</span>cout<<A[i]<<" ";
<span style="white-space:pre">	</span>cout<<endl;
<span style="white-space:pre">	</span>heapsort(A,10);
<span style="white-space:pre">	</span>cout<<"A 堆排序后:  ";
<span style="white-space:pre">	</span>for(int j=1;j<=10;j++)
<span style="white-space:pre">		</span>cout<<A[j]<<" ";
<span style="white-space:pre">	</span>cout<<endl;
}

总结:堆排序不是稳定排序,因为它是跳跃交换数据的。但堆排序是原址排序,排序时只需常数个额外的元素空间存储临时数据。
 


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值