《算法导论(第三版)》笔记——堆排序(Heapsort)

堆排序是利用数据结构(heap),进行排序的一种方式。理解起来需要花费一番功夫。笔者在阅读《算法导论》之后,根据伪代码写出了代码,现附录于下,建议配合原书中图片一起理解。

测试代码

先给出测试代码,因为其中定义的一些全局变量可能下面的函数需要使用。先注意里面的全局变量,至于调用的函数是什么意思,下面会有解释。

#include<iostream>
using namespace std;


//0占去A[0];
int A[]={0,16,14,10,9,8,7,4,3,2,1};
//从A[1]开始。算作第一个。所以A的长度减一(减去A[0])
int length=sizeof(A)/sizeof(int)-1;
//length之后要改变,所以和k分开。
int k=sizeof(A)/sizeof(int)-1;



//镶嵌函数部分。




int main()
 {
  for(int i=1;i<=k;i++)
  {
      Left(i);
      Right(i);
      Parent(i);
  }
  Heapsort(A);
  for(int i=1;i<=k;i++)
  {
      cout<<A[i]<<' ';
  }
 }

“堆”
伪代码在英文原版152页

本段代码的目的是把每个节点的“父节点”(母节点)和“子节点”找出来,编号原则具体看本节内容的图片。

//编号i节点的父节点
int Parent(int i)
 {
     return i/2;
 }

//左子节点
 int Left(int i)
 {
     return 2*i;
 }

//右子节点
 int Right(int i)
 {
     return 2*i+1;
 }

维护“堆”的性质
原书154页

本节代码的目的是维护“堆”的性质,即使得父节点里的值要比子节点大,抽象起来就是“堆”,但具体使用起来有些细节要注意。

void Max_heapify(int* A,int i)
 {
     int l=Left(i);
     int r=Right(i);
     int largest;

     if(l<=length&&A[l]>A[i])
            largest=l;
     else largest=i;
     if(r<=length&&A[r]>A[largest])
        largest=r;
     if(largest!=i)
     {
         int t=A[i];
         A[i]=A[largest];
         A[largest]=t;
         Max_heapify(A,largest);
     }

 }

可以看出,对于一个组成堆得基本元素(一个父节点,两个子节点),以上函数总是将节点中最大的值放到父节点上,有读者可能想到,由于函数是递归的,调用子节点的子节点时,会不会使得子节点的子节点中的值交换到子节点上,从而使得子节点中的值又大于了父节点呢(有些拗口,但意思应该明确),别急,还有下面的函数。

构建堆

 void Build_max_heap(int* A)
 {

     for(int i=k/2;i>=1;i--)
     {
         Max_heapify(A,i);
     }
 }

可以看出,从编号大的节点到编号小的节点,分别运行所示函数,可以构建出一个严格的堆,即父节点一定大于子节点。k是数组长度,数学证明从k/2开始即可,有兴趣可见原书。这里有一个简单地论证方法。假设堆(二叉树)呈现一个完整的“金字塔形”,假设最底层有2n个节点(可知最底层是第n+1层),那么以上n层的节点总和,根据等比数列求和,一共是2n-1个,所以如果k是节点总数的话,k/2号节点一定落在倒数第二层。这样在更下面(编号更大)的节点上运行了Max_heapify()函数,可以构建一个堆,是数列的最大值在A[1]中。

排序
原书160页

接下来就是排序了,

 void Heapsort(int *A)
 {

     Build_max_heap(A);
     for(int i=k;i>=2;i--)
     {
         int t=A[1];
         A[1]=A[i];
         A[i]=t;
         //堆排序之后最大的A[1],放在最后的位置A[i]上面,相当于数字“归位了。
         //长度减1,下面的函数就不会再排A[i]了;
         length--;
         Max_heapify(A,1);

     }
 }

至此结束。水平所限,欢迎指出纰漏。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值