算法熟记-排序系列-堆排序

1. 简述

    假设待排序数组为 int array[], 数组长度为n。
    主要是利用堆的性质。对于升序排序,使用最大堆。
    首先,建堆,使用递归后根序遍历得方法,通过交换元素,保证根元素比孩子元素大。
    第1趟,堆顶元素array[0]与array[n-1]交换,保证array[n-1]的数值正确,根据array[0]新的数值更新堆。
    第2趟,堆顶元素array[0]与array[n-2]交换,保证array[n-2]的数值正确,根据array[0]新的数值更新堆。
    ···

    第n-1趟,堆顶元素array[0]与array[1]交换,保证array[1]的数值正确,根据array[0]新的数值更新堆。

2. 复杂度

    平均时间复杂度为O(N*logN),空间复杂度为O(1)。

3. 代码   

void  make_heap( int  array[],  int  n,  int  node) {  //  自底向上,构建堆
   int  left  =   2   *  node + 1;
  
int  right  =   2   *  node  +  2 ;
  
if (left  >  n - 1 return ;
  
else   if (right  >  n - 1 ) {  //  堆是完全的二叉树,所以此时不需要递归
     if (array[node]  <  array[left]) {
      swap(array[node], array[left]);
    }
  }
  
else  {
    make_heap(array, n, left);
    make_heap(array, n, right);
    
if (array[node]  <  array[left]  &&  array[right]  <=  array[left]) {
      swap(array[node], array[left]);
    }
    
else   if (array[node]  <  array[right]  &&  array[left]  <=  array[right]) {
      swap(array[node], array[right]);
    }
  }
}
void  update_heap( int  array[],  int  n,  int  node) {  //  自顶向下,更新堆
   int  left  =   2   *  n + 1;
  
int  right  =   2   *  n  +  2 ;
  
if (left  >  n - 1 return ;
  
else   if (right  >  n - 1 ) {
    
if (array[node]  <  array[left]) 
      swap(array[node], array[left]);
  }
  
else  {
    
if (array[node]  <  array[left]  &&  array[right]  <=  array[left]) {
      swap(array[node], array[left]);
      update_heap(array, n, left);
    }
    
else   if (array[node]  <  array[right]  &&  array[left]  <=  array[right]) {
      swap(array[node], array[right]);
      update_heap(array, n, right);
    }
  }
}
void  heap_sort( int  array[],  int  n) {
  make_heap(array, n, 
0 );
  
for ( int  i = n; i >= 1 ; i -- ) {
    swap(array[i], array[
0 ]);
    update_heap(array, n, node);
  } 
}

    实际上,堆的构建和更新都可以使用非递归的方式实现,对于堆的构建,需要首先找到最后一个有孩子的节点array[k],然后从array[k]一直更新到array[0]即可,其中的k=n/2。k的求法如下:假设k存在,2*k+1=n或者2*k+2=n,对于第一种情况,k==n/2,对于第二种情况,k==n/2-1。对于堆的更新,就更简单了,只要从array[0]开始,选择一条通路,一直向下更新,直到没有孩子了为止。
   值得注意的是,对于下标从0开始的数组,k号节点的孩子节点分别是2*k+1和2*k+2。 而对于下标从1开始得数组,k号节点的孩子节点分别是2*k和2*k+1。
    堆排序属于选择排序,实际上就是利用最大堆这个数据结构,每次选择一个剩余元素中最大的元素,交换到合适的位置上去。

4. 参考资料

    维基百科-堆排序    http://en.wikipedia.org/wiki/Heapsort

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值