-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathHeap.cc
More file actions
160 lines (132 loc) · 3.61 KB
/
Heap.cc
File metadata and controls
160 lines (132 loc) · 3.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#include <iostream>
#include <vector>
#include <algorithm>
#include <random>
class FixedMaxHeap {
public:
FixedMaxHeap(size_t capacity): cap_(capacity) {
data_.reserve(cap_+1);
// use an sentinel in the
data_.push_back(INT_MAX);
// if we set a sentinel in position 0, then the binary
// heap looks like:
// 0
// |
// 1
// / \
// 2 3
// and we will have some really nice properties:
// 1. parent(index) = index/2
// 2. children(index) = index*2, index*2+1(maybe exist or not)
// 3. we need not check the if the index overflow every time
}
size_t size() const {
return data_.size()-1;
}
bool isFull() const {
return size() == cap_;
}
bool isEmpty() const {
return size() == 0;
}
// will raise exception when there is no element
int top() const {
if (isEmpty()) {
throw std::invalid_argument("heap is empty");
}
return data_[ROOT_IDX];
}
void push(int val) {
if (isFull()) {
throw std::invalid_argument("heap is full");
}
std::cout << "try to push: " << val << std::endl;
data_.push_back(val);
adjustUp();
}
int pop() {
if (isEmpty()) {
throw std::invalid_argument("heap is empty");
}
std::cout << "try to pop: " << top() << std::endl;
int val = top();
data_[ROOT_IDX] = data_.back();
data_.pop_back(); // shrink
adjustDown(); // make it a heap again
return val;
}
private:
// insert from bottom level to the root
// suppose that: only the last value does not
// compose the heap properties
void adjustUp() {
size_t pos = data_.size() - 1;
int val = data_[pos];
for (; data_[pos/2] < data_[pos]; pos /= 2) {
data_[pos] = data_[pos/2];
}
if (pos != data_.size()-1) {
data_[pos] = val;
}
}
// adjust from the root to the bottom
// suppose that: only the root value does not
// compose the heap properties
void adjustDown() {
size_t pos = ROOT_IDX;
int val = data_[pos];
while (pos*2 < data_.size()) {
size_t child = pos * 2;
// find the larger one to be poped
if (child+1 < data_.size() && data_[child+1] > data_[child]) {
child++;
}
if (data_[child] > data_[pos]) {
data_[pos] = data_[child];
pos = child;
} else {
break;
}
}
if (pos != ROOT_IDX) {
data_[pos] = val;
}
}
public:
void echo() { // for debug
for (size_t i = ROOT_IDX; i < data_.size(); ++i) {
std::cout << data_[i] << " ";
}
std::cout << std::endl;
}
private:
static const size_t ROOT_IDX = 1;
size_t cap_;
std::vector<int> data_;
};
int main() {
std::vector<int> data(100);
for (int i = 0; i < 100; ++i) {
data[i] = i;
}
std::random_device rd;
std::mt19937 rng(rd());
std::shuffle(data.begin(), data.end(), rng);
// find top 5 smallest number
FixedMaxHeap q(5);
for (auto num: data) {
if (!q.isFull()) {
q.push(num);
} else if (num < q.top()) {
q.pop();
q.push(num);
}
q.echo();
}
std::cout << "The smallest 5 number are:" << std::endl;
while (!q.isEmpty()) {
std::cout << q.top() << " ";
q.pop();
}
return 0;
}