前一陣子一直在寫排序的系列文章,最近由於一些事情耽擱了幾天,也穿插了幾篇其餘類別的隨筆。今天仍是回到排序上面來,有始有終,呵呵。
今天要介紹的也是一種效率很高的排序——堆排序
思想
堆排序,顧名思義,就是基於堆。所以先來介紹一下堆的概念。
堆分爲最大堆和最小堆,其實就是徹底二叉樹。最大堆要求節點的元素都要大於其孩子,最小堆要求節點元素都小於其左右孩子,二者對左右孩子的大小關係不作任何要求,其實很好理解。有了上面的定義,咱們能夠得知,處於最大堆的根節點的元素必定是這個堆中的最大值。其實咱們的堆排序算法就是抓住了堆的這一特色,每次都取堆頂的元素,將其放在序列最後面,而後將剩餘的元素從新調整爲最大堆,依次類推,最終獲得排序的序列。
或者說,堆排序將全部的待排序數據分爲兩部分,無序區和有序區。無序區也就是前面的最大堆數據,有序區是每次將堆頂元素放到最後排列而成的序列。每一次堆排序過程都是有序區元素個數增長,無序區元素個數減小的過程。當無序區元素個數爲1時,堆排序就完成了。
本質上講,堆排序是一種選擇排序,每次都選擇堆中最大的元素進行排序。只不過堆排序選擇元素的方法更爲先進,時間複雜度更低,效率更高。
圖例說明一下:(圖片來自http://www.cnblogs.com/zabery/archive/2011/07/26/2117103.html)html
具體步驟以下:node
1 首先從第一個非葉子節點開始,比較當前節點和其孩子節點,將最大的元素放在當前節點,交換當前節點和最大節點元素。算法
2 將當前元素前面全部的元素都進行1的過程,這樣就生成了最大堆post
3 將堆頂元素和最後一個元素交換,列表長度減1。由此無序區減1,有序區加1ui
4 剩餘元素從新調整建堆spa
5 繼續3和4,直到全部元素都完成排序code
代碼htm
int adjust_heap(vector<int> &v, int length, int i){
int left = 2 * i;
int right = 2 * i + 1;
int largest = i;
int temp;
while(left < length || right < length){
if (left < length && v[largest] < v[left]){
largest = left;
}
if (right < length && v[largest] < v[right]){
largest = right;
}
if (i != largest){
temp = v[largest];
v[largest] = v[i];
v[i] = temp;
i = largest;
left = 2 * i;
right = 2 * i + 1;
}
else{
break;
}
}
}
int build_heap(vector<int> &v, int length){
int i;
int begin = length/2 - 1; //get the last parent node
for (i = begin; i>=0; i--){
adjust_heap(v,length,i);
}
}
int heap_sort(vector<int> &v){
int length = v.size();
int temp;
printline("before sort:",v);
build_heap(v,length);
while(length > 1){
temp = v[length-1];
v[length-1] = v[0];
v[0] = temp;
length--;
adjust_heap(v,length,0);
}
printline("after sort:",v);
}
分析
堆排序的平均時間複雜度爲O(nlogn),接近於最壞的時間複雜度。在最好狀況下,時間複雜度爲O(1).blog