堆栈 ——堆排序

最近看树比较多,总结一下堆的算法吧,

堆得定义:(个人觉得和二叉排序树很像,只是堆可以看做是一颗完全二叉树)

         n个关键字序列Kl,K2,…,Kn称为(Heap),当且仅当该序列满足如下性质:

  ki<=k(2i)且ki<=k(2i+1)(1≤i≤ n/2),当然,这是小根堆,大根堆则换成>=号
  k(i)相当于二叉树的非叶子结点,K(2i)则是左子节点,k(2i+1)是右子节点;
若将此序列所存储的向量R[1..n]看做是一棵完全二叉树存储结构,则堆实质上是满足如下性质的完全二叉树:
树中任一非叶子结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字。
                                        
既然是堆呢,那么首先考虑的肯定如何构建堆(以大根堆为列):
根据完全二叉树的性质我们可以知道对于一个有n个节点的树,有[n/2](取上整数)个节点是叶子节点,所以构建时字需要对前n/2个节点进行递归维护就是了,
维护就是让这颗树保持堆的性质,其步奏为:
  1. 比较当前节点与其左子树节点的大小,如果小于则记录,
  2. 比较当前节点和右子树的大小,如果小于则记录
  3. 如果前根节点需要交换,则交换节点值,并对交换的子树进行同样的维护操作;      

根据这个思路代码也就不难了:
void HeapAdjust(int *A, int i, int HeapSize){
    int lchild= i*2;
    int rchild= i*2+1;
    int maxi= i;

    if(lchild<=HeapSize && A[i] < A[lchild])
        maxi= lchild;
    if(rchild<=HeapSize&& A[maxi] < A[rchild] )
        maxi = rchild;
    if(maxi != i ){
        int tmp = A[i];
        A[i]= A[maxi];
        A[maxi]= tmp;
        HeapAdjust(A, maxi, HeapSize);
    }

}

于是呢构建堆得代码就有很好写了:
void bulidmaxheap(int *A, int n){
    for(int i=n/2;i>=1;i--)
        HeapAdjust(A, i, n);
}


 堆排序呢也就更简单了,应为我们已经把大根堆构建出来了,所以第一个节点就是最大元素咯,                                                                      所以排序的过程就是:                                                                                                                                               将第一个节点的值和最后一个节点的值交换                                                                                                                    维护现有堆                                                                                                                                                进行第一步一直到堆得size为0;                                                                                                                      根据这样的代码就有了下面的代码:                                                                                                                      void HeapSort(int *A, int n){
    bulidmaxheap(A, n);
    for(int i=n;i>=1;i--){
        int tmp= A[i];
        A[i]= A[1];
        A[1]= tmp;
        HeapAdjust(A,1,i-1);
    }
}


 
  为了方便树对孩子节点的计算,我们在数组中的元素,下标都是从1开始;
下面是测试:
<pre name="code" class="cpp">int main()
{
    int A[10]={0,1,8,5,6,9,7,2,3,4};
    cout<< "原数组:"<<endl;
    for(int i=0;i<10;i++)
        cout<< A[i] << "  ";
    cout<<endl;
    bulidmaxheap(A,9);
    cout<< "大根堆数组:"<<endl;
    for(int i=0;i<10;i++)
        cout<< A[i] << "  ";
    cout<<endl;
    HeapSort(A, 9);
    cout<< "堆排序后的数组:"<<endl;
    for(int i=0;i<10;i++)
        cout<< A[i] << "  ";
    cout<<endl;
    return 0;
}


 
 
 应为第一个元素没有用到,随便赋了个0值,无影响,测试结果为: 
          
在顺便说一下堆得应用,就是游侠你队列,priority_queue 在头文件queue里,直接定义一个优先级关系就可以调用了,感觉特别方便;





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值