前言 :
堆積排序法 可以算是 選擇排序法 的改進版, 它可以減少在選擇排序中的比較次數, 進而減少排序時間. 堆積排序法使用到 二元樹 的技巧, 它是利用堆積樹來完成排序. 堆積是一種特殊的二元樹, 可以分為最大堆積樹及最小堆積樹兩種. 而最大堆積數滿足以下3 個條件 :
而最小堆積數則具備以下3個條件 :
在開始討論堆積排序法前, 先介紹如何將二元樹轉換成堆積數 (Heap Tree). 將以下面實例進行說明 :
Step1 : A[0] = 32 為樹根, A[1] = 17 < A[0] = 32, 不用交換.
Step2 : A[2] = 16 < A[0], 不用交換
Step3 : A[3] = 24 > A[1] = 17 故交換. A[3] = 24 < A[0] = 32, 不用交換
Step4 : A[4] = 35 > A[1] = 24 故交換, A[1] = 35 > A[0] 故交換
Step5 : A[5] = 87 > A[2] = 16 故交換, A[2] = 87 > A[0] = 35 故交換
Step6 : A[6] = 65 > A[2] = 35 故交換, A[2] = 65 < A[0] = 87 故不必交換. 最後 A[7] 與 A[8] 都不必交換, 所以下面為最後的堆積數.
藉由上面示範由二元樹轉換成堆積數, 可以知道堆積樹並非唯一. 至於堆積排序法的演算法就是從樹根取出最大值後, 再從原來的堆積數重新建立堆積數, 然後再依序從樹根取出值來得到排序的結果, 直到原來的堆積數元素為零為止.
堆積演算法分析 :
範例代碼 :
執行結果 :
Ruby Sample Code
堆積排序法 可以算是 選擇排序法 的改進版, 它可以減少在選擇排序中的比較次數, 進而減少排序時間. 堆積排序法使用到 二元樹 的技巧, 它是利用堆積樹來完成排序. 堆積是一種特殊的二元樹, 可以分為最大堆積樹及最小堆積樹兩種. 而最大堆積數滿足以下3 個條件 :
而最小堆積數則具備以下3個條件 :
在開始討論堆積排序法前, 先介紹如何將二元樹轉換成堆積數 (Heap Tree). 將以下面實例進行說明 :
Step1 : A[0] = 32 為樹根, A[1] = 17 < A[0] = 32, 不用交換.
Step2 : A[2] = 16 < A[0], 不用交換
Step3 : A[3] = 24 > A[1] = 17 故交換. A[3] = 24 < A[0] = 32, 不用交換
Step4 : A[4] = 35 > A[1] = 24 故交換, A[1] = 35 > A[0] 故交換
Step5 : A[5] = 87 > A[2] = 16 故交換, A[2] = 87 > A[0] = 35 故交換
Step6 : A[6] = 65 > A[2] = 35 故交換, A[2] = 65 < A[0] = 87 故不必交換. 最後 A[7] 與 A[8] 都不必交換, 所以下面為最後的堆積數.
藉由上面示範由二元樹轉換成堆積數, 可以知道堆積樹並非唯一. 至於堆積排序法的演算法就是從樹根取出最大值後, 再從原來的堆積數重新建立堆積數, 然後再依序從樹根取出值來得到排序的結果, 直到原來的堆積數元素為零為止.
堆積演算法分析 :
範例代碼 :
- #include
- #include
- using namespace std;
- struct BenchMark {
- int swapTime; // Swap Time
- int verifyTime; // Verify Time
- double cTime; // Consumed Time
- };
- void _swapValue(int *a, int *b) {
- int tmp = *a;
- *a = *b;
- *b = tmp;
- }
- int _gp(int v) {
- if(v>0) {
- int tmp = v/2;
- if(v%2==0)
- return tmp-1;
- else
- return tmp;
- }
- return 0;
- }
- BenchMark _ad_heap(int data[], int i, int size) {
- BenchMark bm;
- int vt=0, st=0;
- for(int j=i; j>0; j--) {
- int tmp = j;
- int k = _gp(j);
- while(k>=0) {
- vt++;
- if(data[tmp] > data[k]) {
- st++;
- _swapValue(&data[tmp], &data[k]);
- tmp = k;
- } else {
- break;
- }
- if(k==0)
- break;
- k = _gp(k);
- }
- }
- bm.swapTime = st;
- bm.verifyTime = vt;
- return bm;
- }
- BenchMark heapSort(int data[], int size) {
- BenchMark bm;
- BenchMark tmpBM;
- bm.swapTime = 0;
- bm.verifyTime = 0;
- /*建立堆積樹*/
- tmpBM = _ad_heap(data, size, size);
- bm.swapTime+= tmpBM.swapTime;
- bm.verifyTime+=tmpBM.verifyTime;
- printf("堆積樹內容: \n");
- for(int i=0; i
- printf("%2d ", data[i]);
- }
- printf("\n");
- for(int i=(size-1); i>=0; i--) {
- _swapValue(&data[i], &data[0]);
- tmpBM = _ad_heap(data, i-1,size);
- bm.swapTime+= tmpBM.swapTime;
- bm.verifyTime+=tmpBM.verifyTime;
- }
- return bm;
- }
- void _showData(int data[], int size) {
- for(int i=0; i
- printf("%2d ", data[i]);
- }
- printf("\n");
- }
- #define HEAP_DATA_SIZE 9
- void main(bool b) {
- int data[HEAP_DATA_SIZE] = {32, 17, 16, 24, 35, 87, 65, 4, 12};
- printf("原始資料為: ");
- _showData(data, HEAP_DATA_SIZE);
- BenchMark bm = heapSort(data, HEAP_DATA_SIZE);
- cout << "堆積排序: " << endl;
- _showData(data, HEAP_DATA_SIZE);
- printf("Swap time: %d\n", bm.swapTime);
- printf("Verify time: %d\n", bm.verifyTime);
- }
Ruby Sample Code
- alg/sort/SortMod.rb
- alg/sort/HeapSort.rb
- Demo Code
Execution result:
- module SortMod
- @@des_cmp = lambda{ |a,b| return a <=> b}
- @@asc_cmp = lambda{ |a,b| return b <=> a}
- # Open API: Sorting given array
. - def sort(ary, desc=true)
- nary = []
- ary.each{ |item|; nary << item; }
- csort(nary, desc ? @@des_cmp : @@asc_cmp)
- nary
- end
- # Customized sorting algorithm.
- def csort(ary, cmp)
- raise RuntimeError, "Muse implement
method!" - end
- # Swap ary[i] with ary[j]
- def swap(ary, i, j)
- ary[i], ary[j] = ary[j], ary[i]
- end
- # Open API: In place sorting on given array
- def sort?(ary, cmp, desc=true)
- csort(ary, cmp, desc ? @@des_cmp : @@asc_cmp)
- cmp
- end
- public :sort, :sort?
- protected :csort, :swap
- end
- require "alg/sort/SortMod"
- class HeapSort
- # http://localhost/jforum/posts/list/963.page
- include SortMod
- # Get Parent
- # 0
- # 1 2
- # 3 4 5 6
- # p = (c-1)/2
- # c=1 -> (1-1)/2 = 0
- # c=2 -> (2-1)/2 = 0
- # c=3 -> (3-1)/2 = 1
- # c=4 -> (4-1)/2 = 1
- # c=5 -> (5-1)/2 = 2
- # c=6 -> (6-1)/2 = 2
- @@GP=lambda{|c| (c-1)/2}
- # Get Child
- # 0
- # 1 2
- # 3 4 5 6
- # c = (p*2+1, p*2+2)
- # p=0 -> 0*2+1=1, 0*2+2=2
- # p=1 -> 1*2+1=3, 1*2+2=4
- # p=2 -> 2*2+1=5, 2*2+2=6
- @@GC=lambda{|p| [p*2+1,p*2+2]}
- # Build heap-tree
- def _ad_heap(ary, cmp, size)
- (size-1).downto(1) do |i|
- p=@@GP.call(i)
- while p>=0
- if cmp.call(ary[i], ary[p])==1
- swap(ary, i, p)
- i=p
- p=@@GP.call(p)
- else
- break
- end
- end
- end
- end
- def csort(ary, cmp)
- if ary.size > 1
- ary.size.downto(2) do |i|
- _ad_heap(ary, cmp, i)
- #printf("HeapTree(%d)=%s\n", i, ary)
- swap(ary, 0, i-1)
- end
- end
- ary
- end
- end
- require "alg/sort/HeapSort"
- printf("Heap Sorting Demo:\n")
- heapSort = HeapSort.new
- printf("Original ary: %s\n", a)
- printf("After sort(desc): %s\n", heapSort.sort(a, false))
- printf("After sort(asc) : %s\n", heapSort.sort(a, true))
- printf("Original ary: %s\n\n", a)
沒有留言:
張貼留言