堆排序 [Algorithm]

來源:互聯網
上載者:User
老生常談:

      插入排序最壞情況O(n2), 其內迴圈比較緊湊,對於小規模輸入是一個快速的原地(數組中某個局部)排序演算法。歸併排序有著漸進已耗用時間nlgn時間,merge不在原地操作(merge最用在整個數組中)。堆排序正是前面兩者優點的整合,在nlgn時間,對n個數進行原地排序[1]

 分析

      堆是典型的完全二叉樹,n個元素的堆數組中。

      n/2(隱式下取整)+1 開始是葉子節點。證明:對於任意下標為i(從0開始)的非葉子節點,有性質:2*i+1, 2*i+2為其左右孩子,有2*i+1 <= n  and  2*i+2 <= n, 則最後一個非葉子結點為(int)n/2。下一個n/2+1為葉子節點。 

      堆排序關鍵是一個調整函數,每次遞迴調整某個子樹,使其保持最大堆或者最小堆的性質,這個函數的一個細節是作用範圍,以函數參數的形式傳入。

 

代碼實現

      程式中,通過宏在debug模式下,增加了一些“腳手架”,所謂的腳手架就是程式中加入輸出以觀察運行過程,度量代碼以及組件測試的方法[2]。這種協助工具輔助,有點像工業製造中的工裝,工裝”即生產過程工藝裝備指製造過程中所用的各種工具的總稱。包括刀具/夾具/模具/量具/檢具/輔具/鉗工工具/工位器具等[3]

      有了腳手架的代碼,看上去就不那麼整齊,就像去工地一樣,布滿工裝,肯定沒有裝修好的高樓大廈整潔乾淨~ 下面是整個代碼:

#include <iostream><br />#include <algorithm><br />#include <vector><br />#include <ctime><br />#include <cassert></p><p>using namespace std;</p><p>void swap(int& a, int& b)<br />{<br />typedef int type;</p><p>type temp = a;<br />a = b;<br />b = temp;<br />}</p><p>/** 調節第i個結點,使儲存最大堆特性<br /> @param ptr 數組指標<br /> @param range 堆調整的作用範圍[0, range-1]<br /> @param i 當前被調節的結點<br /> **/<br />void max_heapify(int* ptr, int range, int i)<br />{<br />typedef int type;<br />typedef type* ptr_type;</p><p>int left = i*2+1;<br />int right = i*2+2;</p><p>int largest;//記錄left, i, right中最大元素下標</p><p>//if ( left <= length && ptr[left] > ptr[i] )<br />if ( left < range && ptr[left] > ptr[i] )<br />largest = left;<br />else<br />largest = i;</p><p>//if ( right <= length && ptr[right] > ptr[largest] )<br />//if ( right <= length && ptr[right] > ptr[i] )<br />if ( right < range && ptr[right] > ptr[largest] )<br />largest = right;</p><p>if (largest!=i)<br />{<br />swap(ptr[i], ptr[largest]);</p><p>max_heapify(ptr, range, largest);<br />}<br />}</p><p>void build_max_heap(int* ptr, int length)<br />{<br />typedef int type;<br />typedef type* ptr_type;</p><p>int end = length/2;//end+1: first leaf position</p><p>//for (int i(0); i<end; i++)<br />for (int i=end-1; i>=0; i--)<br />max_heapify(ptr, length, i);<br />}</p><p>//<br />void heap_sort(int* ptr, int length)<br />{<br />typedef int type;<br />typedef type* ptr_type;</p><p>build_max_heap(ptr, length);</p><p>#ifdef _DEBUG<br />cout << "The max heap is: " << endl;<br />for (int t(0); t<length; t++) cout << ptr[t] << " ";<br />cout << endl;</p><p>cout << "Heap sort process: " << endl;<br />#endif</p><p>for (int lastId(length-1); lastId; lastId--)<br />{<br />swap(ptr[0], ptr[lastId]);</p><p>#ifdef _DEBUG<br />for (int t(0); t<lastId; t++) cout << ptr[t] << " ";<br />cout << "--";<br />#endif<br />max_heapify(ptr, lastId, 0);//adjust [0, lastId-1].</p><p>#ifdef _DEBUG<br />for (int t(lastId); t<length; t++) cout << ptr[t] << " ";<br />cout << endl;<br />#endif<br />}<br />}</p><p>bool larger(int left, int right)<br />{<br />return left < right;<br />}</p><p>int main ()<br />{<br />#define P_2</p><p>#ifdef P_1<br />{<br />int myints[] = {10,20,30,5,15};<br />vector<int> v(myints,myints+5);<br />vector<int>::iterator it;</p><p>make_heap (v.begin(),v.end());<br />sort_heap (v.begin(),v.end());</p><p>cout << "final sorted range :";<br />for (unsigned i=0; i<v.size(); i++) cout << " " << v[i];<br />cout << endl;<br />}<br />#endif // P_1</p><p>#ifdef P_2<br />{<br />const int test_num = 10000000;// 1 million<br />srand((int)time(0));</p><p>cout << "Test number " << "/t:/t/t" << test_num << std::endl;</p><p>int* testPtr = new int[test_num];<br />int* testPtr1 = new int[test_num];</p><p>for(int idx=0; idx<test_num; idx++)<br />testPtr1[idx] = testPtr[idx] = rand();</p><p>clock_t t = clock();<br />//build_max_heap(testPtr, test_num);<br />heap_sort(testPtr, test_num);<br />cout << "heap_sort " << "/t:/t/t" << clock() - t << std::endl;</p><p>t = clock();<br />make_heap(testPtr1, testPtr1+test_num, larger);<br />std::sort_heap(testPtr1, testPtr1+test_num, larger);<br />cout << "std::sort_heap " << "/t:/t/t" << clock() - t << std::endl;</p><p>// Test the result validity<br />for(int idx=0; idx<test_num; idx++)<br />if (testPtr[idx]!=testPtr1[idx])<br />cout << "wrong";</p><p>delete[] testPtr;testPtr = 0;<br />delete[] testPtr1;testPtr1 = 0;<br />}<br />#endif // P_2</p><p>#ifdef P_3<br />{<br />int myints[] = {5,2,4,7,1,3,6};<br />int length = sizeof(myints)/sizeof(myints[0]);</p><p>heap_sort(myints, length);<br />cout << endl;<br />for (int i(0); i<length; i++) cout << myints[i] << " ";<br />cout << endl;<br />}<br />#endif // P_3</p><p>system("PAUSE");</p><p>return 0;<br />}

 

自己寫的heap_sort與STL的sort_heap比,效率差了點(主要是驗證思路),實驗結果如下:

Test number : 10000000<br />heap_sort : 7734<br />std::sort_heap : 5556

後記

     建堆有兩種方案:一種思路從最後一個父親結點,逆序調整堆;另一種思路是從第二個元素開始插入法建堆。STL中是插入法建堆。插入法建大頂堆的思路:先將一個最小數字放到堆末尾,此時滿足最大堆性質;然後迴圈增加索引值,保持大頂堆的性質。

始終有個疑問,這種插入法建立的堆是否是唯一的?測試結果:對於一堆相同的輸入,插入法建堆,調整方式建堆,和STL建堆 結果都不一樣~

代碼如下:

 void heap_increase_key(int* ptr, int pos, int key)<br />{<br />ptr[pos] = key;</p><p>int parent = (pos-1)/2;<br />while( pos>=0 && ptr[parent]<ptr[pos] )<br />{<br />swap(ptr[pos], ptr[parent]);<br />pos = parent;</p><p>parent = (pos-1)/2;</p><p>// pos is 0 ==> parent is 0<br />// ptr[parent]==ptr[pos]<br />// exit the while loop<br />}<br />}</p><p>void heap_insert_key(int* ptr, int& lastId, int key)<br />{<br />//lastId++;</p><p>int imin = std::numeric_limits<int>::min();<br />ptr[lastId] = imin;</p><p>heap_increase_key(ptr, lastId, key);<br />}</p><p>void insert_build_max_heap(int* ptr, int length)<br />{<br />typedef int type;<br />typedef type* ptr_type;</p><p>for (int i=1; i<length; i++)<br />heap_insert_key(ptr, i, ptr[i]);<br />}

add - 2010/12/8 p.m

 

[1] 演算法導論 - 堆排序

[2] 編程珠璣 - 程式員的懺悔

[3] 百度百科 - 工裝 http://baike.baidu.com/view/907594.htm

add - 2011/9/21 p.m

Find_Top_K問題:數組N中尋找最大的K個元素:

用前K[0 - k-1]個元素,建立小頂堆K-Min-Heap;

遍曆K - N-1元素,和堆頂元素比較:

小於跳過,

大於則替換堆頂元素,調整K-Min-Heap結構使之保持小頂堆特性;

K-Heap的操作時間為log2(k)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.