在《演算法設計技巧與分析》這本書的第四章,介紹了堆。於是按照上面的虛擬碼實現了一下。
資料結構定義maxHeap.hpp如下,
1 #ifndef MAX_HEAP_HPP_
2 #define MAX_HEAP_HPP_
3
4 #include <vector>
5 using std::vector;
6
7 class MaxHeap
8 {
9 public:
10 MaxHeap(vector<int>& A);
11 void Insert(int x);
12 int DeleteMax();
13 void Sort();
14 void Print();
15 private:
16 void SiftUp(int i);
17 void SiftDown(int i);
18 void Delete(int i);
19
20 private:
21 vector<int> array;
22 };
23
24 #endif
實現maxHeap.cpp如下
1 #include "maxHeap.hpp"
2
3 #include <vector>
4 #include <iostream>
5 using std::vector;
6 using std::cout;
7 using std::endl;
8
9 MaxHeap::MaxHeap(vector<int>& A)
10 {
11 int i = 0;
12 array = vector<int>(A.size()+1);
13 for(i=1;i<A.size()+1;i++)
14 array[i] = A[i-1];
15 int n = array.size()-1;
16 for(i=n>>1;i>0;i--)
17 {
18 // cout << "i:" << i << "\t array[i]:" << array[i] << endl;
19 SiftDown(i);
20 // Print();
21 }
22 }
23
24 void MaxHeap::SiftUp(int i)
25 {
26 if(i==1)
27 return;
28 int tmp = 0;
29 while(true)
30 {
31 if(array[i]>array[i>>1])
32 {
33 tmp = array[i];
34 array[i] = array[i>>1];
35 array[i>>1] = tmp;
36 }
37 else
38 break;
39 i = i>>1;
40 if(i==1)
41 break;
42 }
43 }
44
45 void MaxHeap::SiftDown(int i)
46 {
47 if((i<<1)>array.size()-1)
48 return;
49 int tmp = 0;
50 while(true)
51 {
52 i = i<<1;
53 if(i+1<=array.size()-1 && array[i+1]>array[i])
54 i = i+1;
55 if(array[i>>1]<array[i])
56 {
57 tmp = array[i];
58 array[i] = array[i>>1];
59 array[i>>1] = tmp;
60 }
61 else
62 break;
63 if((i<<1)>array.size()-1)
64 break;
65 }
66 }
67
68 void MaxHeap::Insert(int x)
69 {
70 array.push_back(x);
71 SiftUp(array.size()-1);
72 }
73
74 void MaxHeap::Delete(int i)
75 {
76 int x = array[i];
77 int y = array[array.size()-1];
78 array.pop_back();
79 if(i==array.size())
80 return;
81 array[i] = y;
82 if(y>=x)
83 SiftUp(i);
84 else
85 SiftDown(i);
86 }
87
88 int MaxHeap::DeleteMax()
89 {
90 int x = array[1];
91 Delete(1);
92 return x;
93 }
94
95 void MaxHeap::Sort()
96 {
97 int i = 0;
98 int n = array.size();
99 vector<int> sortedArray(n,0);
100 for(i=1;i<n;i++)
101 {
102 sortedArray[i] = DeleteMax();
103 Print();
104 }
105 array = sortedArray;
106 }
107
108 void MaxHeap::Print()
109 {
110 cout << "Heap Array:" << endl;
111 int i = 0;
112 for(i=1;i<array.size();i++)
113 cout << "\t" << array[i] ;
114 cout << endl;
115 }
最後的測試主程式main.cpp如下:
1 #include "maxHeap.hpp"
2
3 #include <vector>
4 #include <iostream>
5 using std::vector;
6 using std::cout;
7 using std::endl;
8
9 int main()
10 {
11 //int D[]= {1, 6, 7, 10, 9, 3, 5, 8};
12 int D[] = { 5, 7, 3, 6, 4, 11, 10, 9, 17, 20};
13 cout << "original array:" << endl;
14 for(int i=0;i<10;i++)
15 cout << "\t" << D[i];
16 cout << endl;
17 vector<int> A(D,D+sizeof(D)/sizeof(int));
18 MaxHeap B(A);
19 B.Print();
20
21 B.Sort();
22 cout << "sorted array:" << endl;
23 B.Print();
24
25 return 0;
26 }
最後的測試結果實現了降序排序。
其實網上已經有很多實現的代碼了,自己實現一下,鍛煉一下。
比較自己的代碼和網上已經實現的代碼(如http://www.cppblog.com/Darren/archive/2009/05/17/80169.html),自己在MaxHeap裡面用了一個vector,網上一般是用一個數組指標結合size實現。
在堆排序的實現中,調用SiftDown(H[1..j-1],1),如果資料結構裡面用的是數組指標,那麼是很好傳遞參數的,SiftDown(array_start,array_length,down_index)三個參數,分別是數組起始位置(這裡是位置,不是地址,因為數組指標已經在資料結構裡面了),數組長度,和要調整的元素位置。而我在資料結構裡面使用的vector,這裡就不是很好辦了,如果要指定只取前j-1個元素,或許需要藉助另外一個vector,進行兩次複製,這就太浪費了。最後勉強使用DeleteMax,每次把最大的元素挑出來,然後實現排序,效率肯定沒有直接調用SiftDown(H[1..j-1],1)好了。
資料結構的定義相當關鍵,會影響到函數的實現和調用方式,影響到程式的效率。
vector雖然很好用,但是也不能濫用。
網上經典的資料結構和演算法的實現,應該多學習學習。