首页 > 技术文章 > heapsort

javier2018 2018-03-07 18:01 原文

堆,我们可以把它看做是一个完全二叉树(本质不是完全二叉树),一般分为大顶堆和小顶堆。在堆排序中大顶堆用于从小到大的排列,小顶堆用于从大到小的排列。堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序。

大致的步骤:

堆排序每次从最后一个非叶子节点开始,比较根与两个孩子的大小关系(如果是小顶堆的话,根要比孩子节点小;如果是大顶堆的话根要比孩子节点大),逐个节点比较最后整棵树的根一定就是值最大(最小)的那个点。之后把它和二叉树的最后一个节点作交换。并脱离二叉树。之后把之前的步骤反复进行直到二叉树只剩一个节点。

树那数组存储的话求最后一个非叶子节点有一个公式:i = arr.length()/2-1。

把上面说的堆排序的步骤抽象成模型就是:构造堆,交换,构造堆,。。。

因此算法函数分为两部分,构造堆函数和交换函数。

交换函数很好解决,就是一个swap

1 void Swap(vector<int> &arr,int index){
2     int temp = arr[0];
3     arr[0] = arr[index];
4     arr[index] = temp;
5 }

而构造堆就要有些难度了(这以大顶堆排序为例)

 1 void adjustHeap(vector<int> &arr,int i,int len){
 2     int temp = arr[i];
 3     for(int k=2*i+1;k<len;k=k*2+1){
 4         //k指向左右孩子中最大的那个 
 5         if(k+1<len && arr[k]<arr[k+1]){
 6             k++;
 7         }
 8         //这里使用了优化方法只需要一次交换 
 9         if(arr[k]>temp){
10             arr[i] = arr[k]; 
11             i = k;
12         }else{
13             break;
14         }
15     }
16     arr[i] = temp;
17 }

最后给出排序函数:

 1 void heapSort(vector<int> &arr){
 2     //第一次初始化堆 
 3     for(int i=arr.size()/2-1;i>=0;i--){
 4         adjustHeap(arr,i,arr.size());
 5     }
 6     //从后往前循环能很好地模拟树的不断缩小 
 7     for(int i = arr.size()-1;i>0;i--){
 8         //交换&构建堆 
 9         Swap(arr,i);
10         adjustHeap(arr,0,i);
11     }
12 }

 

参考:堆排序

 

推荐阅读