111年地方特考三等資料結構
四、二元堆積 (Binary Heap) 是一種優先佇列 (Priority Queue),主要用來管理具有優先權順序的資料物件,每個資料物件具有一個可以界定大小或前後順序的鍵值 (Key),我們在此假設鍵值越低的資料物件有越高的優先權。 (一)請完整描述最小堆積 (Min_Heap) 的定義與相關的操作功能。(5分) (二)請說明堆積排序 (Heap Sort) 的方法並分析其時間複雜度。(5分) (三)若有兩個二元樹 T1 及 T2,其節點具有堆積特性且高度分別是 O(log n)與 O(log m),請提供一個方法將此兩個二元樹結合成為一個節點具有堆積特性的二元樹 T,此方法的時間須為 O(logn+logm)。(10分) |
答:
(一)
1.每一個節點的鍵值必須小於它的子節點的鍵值。特性如下:
(1)每一棵 Min Heap 是一棵完整二元樹。
(2)樹根的鍵值小於左子樹與右子樹的鍵值。
(3)其左子樹與右子樹亦是 Min Heap。
2.最小堆積插入新節點:
(1)先把資料加入到二元樹的最後一個節點。
(2)若不是樹根,則與其父節點比較,小於則交換,繼續往上層比較直到其大於或等於其父 (或已到樹根)。
3.最小堆積刪除節點:
由二元樹的最後一個節點取代,然後進行由上而下調整。
※參考資料:
1.正修科技大學-資料結構-第六章樹狀結構.ppt
2.chapter10-1.pdf
(二)請說明堆積排序 (Heap Sort) 的方法並分析其時間複雜度。(5分)
1.說明:
是選擇排序法的改良版,目的是為了減少選擇排序法的比較次數。而堆積排序法就是利用堆積樹的樹根與最後一個節點交換,再重新建立堆積樹,直到只剩下最後一個節點為止,排序也完成了。
2.時間複雜度:
(1)建立 Max-Heap 會花費 O(n) 時間。說明如下:
T(n) = (k-1)×1+(k-2)×2+(k-3)×22+…+1×2k-2+0×2k-1 ……(1)
T(n)×2 = (k-1)×2+(k-2)×22+(k-3)×23+…+1×2k-1+0×2k ……(2)
(2)-(1)
T(n) = -k+1+2+…+1×2k-1 = -k+1+ = -k+1-2+2k = 2k-k-1 = n-log2(n+1)
= O(n) (∵n = 2k-1,∴ k = log2(n+1))。
註:
k 是樹高,第一層有20個節點,第二層有21個節點,最後一層有2k-1節點。
(2)需要執行 n-1 回合的刪除根節點動作,而每一次的刪除根節點的動作需要花費 O(logn) 時間,總共花費 O(nlogn)。說明如下:
(3)整個 Heap-Sort 花費 O(n)+O(nlogn) ≈ O(nlogn) 時間。
註:
Phase I 建立 heap 時,worst case 所需的 sifts 次數 O(n),Phase II 排序,worst
case 所需的 sifts 次數 O(nlogn)。
(三)
說明:
題目有問題,將「此方法的時間須為 O(logn+logm)」改成「此方法的時間須為 O(n+m)」,執行次數才會合理。
#include <iostream> using namespace std; /* 交換 a 和 b 兩值 */ void swap(int* a, int* b) { int tmp = *a; *a = *b; *b = tmp; } /* Heapify 是指將子樹序列修正至符合 heap ordering 的序列 */ void maxHeapify(int arr[ ], int N, int idx) { if (idx >= N) { return; } int l = 2*idx+1; // 左兒子 int r = 2*idx+2; // 右兒子 int max = idx; // 找出最大值的節點和它的兒子 if (l < N && arr[l] > arr[idx]) { max = l; } if (r < N && arr[r] > arr[max]) { max = r; } if (max != idx) { swap(&arr[max], &arr[idx]); maxHeapify(arr, N, max); // 遞迴呼叫 } } /* 由下而上做最大堆積 */ void buildMaxHeap(int arr[ ], int N) { for (int i = N/2-1; i >= 0; i--) { maxHeapify(arr, N, i); } } /* 合併 a 和 b 堆積樹 */ void mergeHeaps(int merged[ ], int a[ ], int b[ ], int N, int M) { for (int i = 0; i < N; i++) { merged[i] = a[i]; } for (int i = 0;i < M; i++) { merged[N+i] = b[i]; } buildMaxHeap(merged, N+M); } int main( ) { int a[ ] = {10, 5, 6, 2}; int b[ ] = {12, 7, 9}; const int N = sizeof(a)/sizeof(a[0]); const int M = sizeof(b)/sizeof(b[0]); int merged[N+M]; mergeHeaps(merged, a, b, N, M); for (int i = 0; i < N + M; i++) { printf("%d ", merged[i]); } return 0; } |
執行結果:
12 10 9 2 5 7 6
※參考資料:https://www.geeksforgeeks.org/merge-two-binary-max-heaps/
留言列表