Skip to content

Commit 9f5efd4

Browse files
committed
update index maxheap with reverse col
1 parent d09542f commit 9f5efd4

File tree

2 files changed

+358
-0
lines changed

2 files changed

+358
-0
lines changed
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
//
2+
// Created by 3zz.
3+
//
4+
5+
#ifndef INC_08_INDEX_HEAP_SORTTESTHELPER_H
6+
#define INC_08_INDEX_HEAP_SORTTESTHELPER_H
7+
8+
#include <iostream>
9+
#include <algorithm>
10+
#include <string>
11+
#include <ctime>
12+
#include <cassert>
13+
#include <string>
14+
15+
using namespace std;
16+
17+
namespace SortTestHelper
18+
{
19+
20+
// 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR]
21+
int *generateRandomArray(int n, int range_l, int range_r)
22+
{
23+
24+
int *arr = new int[n];
25+
26+
srand(time(NULL));
27+
for (int i = 0; i < n; i++)
28+
arr[i] = rand() % (range_r - range_l + 1) + range_l;
29+
return arr;
30+
}
31+
32+
// 生成一个近乎有序的数组
33+
// 首先生成一个含有[0...n-1]的完全有序数组, 之后随机交换swapTimes对数据
34+
// swapTimes定义了数组的无序程度
35+
int *generateNearlyOrderedArray(int n, int swapTimes)
36+
{
37+
38+
int *arr = new int[n];
39+
for (int i = 0; i < n; i++)
40+
arr[i] = i;
41+
42+
srand(time(NULL));
43+
for (int i = 0; i < swapTimes; i++)
44+
{
45+
int posx = rand() % n;
46+
int posy = rand() % n;
47+
swap(arr[posx], arr[posy]);
48+
}
49+
50+
return arr;
51+
}
52+
53+
// 拷贝整型数组a中的所有元素到一个新的数组, 并返回新的数组
54+
int *copyIntArray(int a[], int n)
55+
{
56+
57+
int *arr = new int[n];
58+
//* 在VS中, copy函数被认为是不安全的, 请大家手动写一遍for循环:)
59+
copy(a, a + n, arr);
60+
return arr;
61+
}
62+
63+
// 打印arr数组的所有内容
64+
template <typename T>
65+
void printArray(T arr[], int n)
66+
{
67+
68+
for (int i = 0; i < n; i++)
69+
cout << arr[i] << " ";
70+
cout << endl;
71+
72+
return;
73+
}
74+
75+
// 判断arr数组是否有序
76+
template <typename T>
77+
bool isSorted(T arr[], int n)
78+
{
79+
80+
for (int i = 0; i < n - 1; i++)
81+
if (arr[i] > arr[i + 1])
82+
return false;
83+
84+
return true;
85+
}
86+
87+
// 测试sort排序算法排序arr数组所得到结果的正确性和算法运行时间
88+
// 将算法的运行时间打印在控制台上
89+
template <typename T>
90+
void testSort(const string &sortName, void (*sort)(T[], int), T arr[], int n)
91+
{
92+
93+
clock_t startTime = clock();
94+
sort(arr, n);
95+
clock_t endTime = clock();
96+
cout << sortName << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << " s" << endl;
97+
98+
assert(isSorted(arr, n));
99+
100+
return;
101+
}
102+
103+
// 测试sort排序算法排序arr数组所得到结果的正确性和算法运行时间
104+
// 将算法的运行时间以double类型返回, 单位为秒(s)
105+
template <typename T>
106+
double testSort(void (*sort)(T[], int), T arr[], int n)
107+
{
108+
109+
clock_t startTime = clock();
110+
sort(arr, n);
111+
clock_t endTime = clock();
112+
113+
assert(isSorted(arr, n));
114+
115+
return double(endTime - startTime) / CLOCKS_PER_SEC;
116+
}
117+
118+
}; // namespace SortTestHelper
119+
120+
#endif //INC_08_INDEX_HEAP_SORTTESTHELPER_H
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
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

Comments
 (0)