堆排序heapSort_legend



堆排序:

(一)定义:

从小到大排序则构建一个最大堆;从大到小排序,则构建一个最小堆。
(二)思想:
1.先建立一个最大堆;
2.然后将最大堆的堆顶元素(0号元素,最大值)与堆的最后一个元素(n-1号元素)交换,这样最后一个元素(n-1号)就保存的是最大值了。然后堆的个数-1;调整堆siftDown,(是从0号到n-2号调整),这样就可以在堆顶获得第二大的元素。
3.重复2;
4.最终从n-1号元素到0号元素,存储的就是递减的顺序。

所以:
(1)递增排序,应该构建一个最大堆。
(2)递减排序,应该构造一个最小堆。

(三)优点,适用于:

(1)优点:
堆的优点在于最快的 找到最大,最小值。取走最大,最小值后重新构成堆,其时间复杂度为O(lgn),其他方法一般至少都需要O(n);
(2)适用于:
1.调度算法中,取最高优先级。
2.求取TopN问题或者第N大/小问题。

(四)步骤:
(1)建堆:
1.siftdown;
2.buildHeap:
(2)堆排序:

(五)代码实现:
/*
从start~end,只有start这个位置不满足最大堆,其余位置满足最大堆的定义。
所以从start到end开始调整。
*/


//注意:siftdown是将start处的值data[strat]保存下来为temp,然后将temp的值不断往下调整。所以每次都是孩子中较大的与temp的比较。
void siftDown(HeapType data[], int start ,int end ){

 int maxChild=start*2+1;//初始化孩子中较大的一个为左孩子。
 HeapType temp=data[start];//保留值,挖一个坑。


 for(;maxChild<=end;){

  if(maxChild+1<=end && data[maxChild]<data[maxChild+1] )
  maxChild++;//取左右孩子中较大的一个。

  if(data[maxChild]<temp) break;
  else {
   data[start]=data[maxChild];//将较大的孩子填充到父节点中。
   //较大的孩子节点有了一个坑
   start=maxChild;//更新父节点为儿子节点,继续向下比较。

maxChild=2*start+1;
  }
 }

 data[start]=temp;

}
/*
构建堆,从下到上的非叶子节点,每一个非叶子节点从上往上的siftDown调整。
n为节点个数,即数组长度。
*/
void buildHeap(HeapType data[], int n){
 int mid=(n-1)/2;

 for(;mid>=0;mid--){
  siftDown(data,mid,n-1);
 }
}

/*
堆排序:n为叶子个数,即数组的长度。
*/
void heapSort(HeapType data[], int n){
 buildHeap(data,n);//先构造一个堆、

 for(int i=n-1;i>=0;i--){

  HeapType temp=data[0];//交换堆顶(0号元素)与堆的最后一个元素。
  data[0]=data[i];
  data[i]=temp;

  sitfDown(data,0,i);//堆的大小i不断的减小
 }
}

(六)堆的应用:

(1)求取TopN问题或者第N大/小问题:

1.topN大(即:最大的N个数),则采用最小堆,且堆顶元素为第N大的元素;
2.topN小(即:最小的N个数),则采用最大堆,且堆顶元素为第N小的元素;

如:已知文件中有10000个数据,求取其中的最大的100个数据,现在的内存限制为100个数据。

思想:
1.前100个数,建立一个最小堆;
2.然后i 从个101~10000, 当前元素data[i]与堆顶比较,如果比堆顶大,则覆盖堆顶,然后siftDown调整。
3.重复2直至结束,则最小堆里则为最大的100个数,且堆顶为第100大的数。

(2)快速求取,最大,最小值。





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值