1
+ #include < iostream>
2
+ #include < cassert>
3
+ #include " SortTestHelper.h"
4
+
5
+ using namespace std ;
6
+
7
+ // 最大索引堆
8
+ template <typename Item>
9
+ class IndexMaxHeap
10
+ {
11
+
12
+ private:
13
+ Item *data; // 最大索引堆中的数据
14
+ int *indexes; // 最大索引堆中的索引
15
+ int *reverse;
16
+ int count;
17
+ int capacity;
18
+
19
+ // 索引堆中, 数据之间的比较根据data的大小进行比较, 但实际操作的是索引
20
+ void shiftUp (int k)
21
+ {
22
+
23
+ while (k > 1 && data[indexes[k / 2 ]] < data[indexes[k]])
24
+ {
25
+ swap (indexes[k / 2 ], indexes[k]);
26
+ reverse[indexes[k / 2 ]] = k / 2 ;
27
+ reverse[indexes[k]] = k;
28
+ k /= 2 ;
29
+ }
30
+ }
31
+
32
+ // 索引堆中, 数据之间的比较根据data的大小进行比较, 但实际操作的是索引
33
+ void shiftDown (int k)
34
+ {
35
+
36
+ while (2 * k <= count)
37
+ {
38
+ int j = 2 * k;
39
+ if (j + 1 <= count && data[indexes[j + 1 ]] > data[indexes[j]])
40
+ j += 1 ;
41
+
42
+ if (data[indexes[k]] >= data[indexes[j]])
43
+ break ;
44
+
45
+ swap (indexes[k], indexes[j]);
46
+ reverse[indexes[k]] = k;
47
+ reverse[indexes[j]] = j;
48
+ k = j;
49
+ }
50
+ }
51
+
52
+ public:
53
+ // 构造函数, 构造一个空的索引堆, 可容纳capacity个元素
54
+ IndexMaxHeap (int capacity)
55
+ {
56
+
57
+ data = new Item[capacity + 1 ];
58
+ indexes = new int [capacity + 1 ];
59
+ reverse = new int [capacity + 1 ];
60
+ for (int i = 0 ; i < capacity; i++)
61
+ reverse[i] = 0 ;
62
+ count = 0 ;
63
+ this ->capacity = capacity;
64
+ }
65
+
66
+ ~IndexMaxHeap ()
67
+ {
68
+ delete[] data;
69
+ delete[] indexes;
70
+ delete[] reverse;
71
+ }
72
+
73
+ // 返回索引堆中的元素个数
74
+ int size ()
75
+ {
76
+ return count;
77
+ }
78
+
79
+ // 返回一个布尔值, 表示索引堆中是否为空
80
+ bool isEmpty ()
81
+ {
82
+ return count == 0 ;
83
+ }
84
+
85
+ // 向最大索引堆中插入一个新的元素, 新元素的索引为i, 元素为item
86
+ // 传入的i对用户而言,是从0索引的
87
+ void insert (int i, Item item)
88
+ {
89
+ assert (count + 1 <= capacity);
90
+ assert (i + 1 >= 1 && i + 1 <= capacity);
91
+
92
+ i += 1 ;
93
+ data[i] = item;
94
+ indexes[count + 1 ] = i;
95
+ reverse[i] = count + 1 ;
96
+ count++;
97
+
98
+ shiftUp (count);
99
+ }
100
+
101
+ // 从最大索引堆中取出堆顶元素, 即索引堆中所存储的最大数据
102
+ Item extractMax ()
103
+ {
104
+ assert (count > 0 );
105
+
106
+ Item ret = data[indexes[1 ]];
107
+ swap (indexes[1 ], indexes[count]);
108
+ reverse[indexes[1 ]] = 1 ;
109
+ reverse[indexes[count]] = 0 ; // 删除
110
+ count--;
111
+ shiftDown (1 );
112
+ return ret;
113
+ }
114
+
115
+ // 从最大索引堆中取出堆顶元素的索引
116
+ int extractMaxIndex ()
117
+ {
118
+ assert (count > 0 );
119
+
120
+ int ret = indexes[1 ] - 1 ;
121
+ swap (indexes[1 ], indexes[count]);
122
+ reverse[indexes[1 ]] = 1 ;
123
+ reverse[indexes[count]] = 0 ; // 删除
124
+ count--;
125
+ shiftDown (1 );
126
+ return ret;
127
+ }
128
+
129
+ // 获取最大索引堆中的堆顶元素
130
+ Item getMax ()
131
+ {
132
+ assert (count > 0 );
133
+ return data[indexes[1 ]];
134
+ }
135
+
136
+ // 获取最大索引堆中的堆顶元素的索引
137
+ int getMaxIndex ()
138
+ {
139
+ assert (count > 0 );
140
+ return indexes[1 ] - 1 ;
141
+ }
142
+ // 获取输入的i是否合法
143
+ bool contain (int i)
144
+ {
145
+ assert (i + 1 >= 1 && i + 1 <= capacity);
146
+ return reverse[i + 1 ] != 0 ;
147
+ }
148
+
149
+ // 获取最大索引堆中索引为i的元素
150
+ Item getItem (int i)
151
+ {
152
+ assert (i + 1 >= 1 && i + 1 <= capacity);
153
+ return data[i + 1 ];
154
+ }
155
+
156
+ // 将最大索引堆中索引为i的元素修改为newItem
157
+ void change (int i, Item newItem)
158
+ {
159
+
160
+ assert (contain (i));
161
+ i += 1 ;
162
+ data[i] = newItem;
163
+
164
+ // 找到indexes[j] = i, j表示data[i]在堆中的位置
165
+ // 之后shiftUp(j), 再shiftDown(j)
166
+ // for (int j = 1; j <= count; j++)
167
+ // if (indexes[j] == i)
168
+ // {
169
+ // shiftUp(j);
170
+ // shiftDown(j);
171
+ // return;
172
+ // }
173
+ int j = reverse[i];
174
+ shiftUp (j);
175
+ shiftDown (j);
176
+ }
177
+
178
+ // 测试索引堆中的索引数组index
179
+ // 注意:这个测试在向堆中插入元素以后, 不进行extract操作有效
180
+ bool testIndexes ()
181
+ {
182
+
183
+ int *copyIndexes = new int [count + 1 ];
184
+
185
+ for (int i = 0 ; i <= count; i++)
186
+ copyIndexes[i] = indexes[i];
187
+
188
+ copyIndexes[0 ] = 0 ;
189
+ std::sort (copyIndexes, copyIndexes + count + 1 );
190
+
191
+ // 在对索引堆中的索引进行排序后, 应该正好是1...count这count个索引
192
+ bool res = true ;
193
+ for (int i = 1 ; i <= count; i++)
194
+ if (copyIndexes[i - 1 ] + 1 != copyIndexes[i])
195
+ {
196
+ res = false ;
197
+ break ;
198
+ }
199
+
200
+ delete[] copyIndexes;
201
+
202
+ if (!res)
203
+ {
204
+ cout << " Error!" << endl;
205
+ return false ;
206
+ }
207
+
208
+ return true ;
209
+ }
210
+ };
211
+
212
+ // 使用最大索引堆进行堆排序, 来验证我们的最大索引堆的正确性
213
+ // 最大索引堆的主要作用不是用于排序, 我们在这里使用排序只是为了验证我们的最大索引堆实现的正确性
214
+ // 在后续的图论中, 无论是最小生成树算法, 还是最短路径算法, 我们都需要使用索引堆进行优化:)
215
+ template <typename T>
216
+ void heapSortUsingIndexMaxHeap (T arr[], int n)
217
+ {
218
+
219
+ IndexMaxHeap<T> indexMaxHeap = IndexMaxHeap<T>(n);
220
+ for (int i = 0 ; i < n; i++)
221
+ indexMaxHeap.insert (i, arr[i]);
222
+ assert (indexMaxHeap.testIndexes ());
223
+
224
+ for (int i = n - 1 ; i >= 0 ; i--)
225
+ arr[i] = indexMaxHeap.extractMax ();
226
+ }
227
+
228
+ int main ()
229
+ {
230
+
231
+ int n = 1000000 ;
232
+
233
+ int *arr = SortTestHelper::generateRandomArray (n, 0 , n);
234
+ SortTestHelper::testSort (" Heap Sort Using Index-Max-Heap" , heapSortUsingIndexMaxHeap, arr, n);
235
+ delete[] arr;
236
+
237
+ return 0 ;
238
+ }
0 commit comments