Skip to content

Commit 8844394

Browse files
authored
Merge pull request #183 from sh0723/implement-minhead-v2
[Data Structure] 최소 힙 V2 구현
2 parents 5aadcff + b10ce59 commit 8844394

1 file changed

Lines changed: 342 additions & 0 deletions

File tree

Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
1+
#include <cassert>
2+
#include <iostream>
3+
#include <stdexcept>
4+
using namespace std;
5+
class MinHeap {
6+
public:
7+
MinHeap();
8+
~MinHeap();
9+
10+
void push(int value);
11+
void pop();
12+
13+
int& top();
14+
15+
int size() const;
16+
int capacity() const;
17+
bool empty() const;
18+
19+
void clear();
20+
void reserve(int newCapacity);
21+
22+
private:
23+
int* data;
24+
int current_size;
25+
int current_capacity;
26+
27+
void siftUp(int index);
28+
void siftDown(int index);
29+
};
30+
// 10:50 시작
31+
MinHeap::MinHeap(): data(nullptr), current_size(0), current_capacity(0) {}
32+
MinHeap::~MinHeap() {
33+
clear();
34+
delete[] data;
35+
}
36+
37+
void MinHeap::push(int value) {
38+
if (current_capacity == current_size) {
39+
reserve(current_capacity == 0 ? 1 : current_capacity * 2);
40+
}
41+
42+
data[current_size] = value;
43+
current_size++;
44+
siftUp(current_size-1);
45+
}
46+
void MinHeap::pop() {
47+
if (current_size == 0) return;
48+
49+
data[0] = data[--current_size];
50+
if (current_size == 0) return;
51+
52+
siftDown(0);
53+
}
54+
55+
int& MinHeap::top() {
56+
if (current_size == 0) throw out_of_range("Heap is Empty.");
57+
58+
return data[0];
59+
}
60+
61+
int MinHeap::size() const {
62+
return current_size;
63+
}
64+
int MinHeap::capacity() const {
65+
return current_capacity;
66+
}
67+
bool MinHeap::empty() const {
68+
return current_size == 0;
69+
}
70+
71+
void MinHeap::clear() {
72+
current_size = 0;
73+
}
74+
void MinHeap::reserve(int newCapacity) {
75+
if (newCapacity <= 0 || newCapacity <= current_capacity) return;
76+
77+
int *newData = new int[newCapacity];
78+
for (int i=0; i<current_size; i++) {
79+
newData[i] = data[i];
80+
}
81+
delete[] data;
82+
data = newData;
83+
current_capacity = newCapacity;
84+
}
85+
void MinHeap::siftUp(int index) {
86+
while(index > 0) {
87+
int parent = (index-1) / 2;
88+
if (data[parent] < data[index]) break;
89+
swap(data[parent], data[index]);
90+
index = parent;
91+
}
92+
}
93+
void MinHeap::siftDown(int index) {
94+
while(index < current_size) {
95+
int left = index * 2 + 1;
96+
int right = index * 2 + 2;
97+
int smallest = index;
98+
99+
if (left < current_size && data[left] < data[smallest]) {
100+
smallest = left;
101+
}
102+
103+
if (right < current_size && data[right] < data[smallest]) {
104+
smallest = right;
105+
}
106+
107+
if (smallest == index) break;
108+
109+
swap(data[index], data[smallest]);
110+
index = smallest;
111+
}
112+
}
113+
int main() {
114+
MinHeap heap;
115+
116+
// 1. 초기 상태
117+
assert(heap.empty());
118+
assert(heap.size() == 0);
119+
assert(heap.capacity() == 0);
120+
121+
// 2. 빈 힙 pop
122+
heap.pop();
123+
124+
assert(heap.empty());
125+
assert(heap.size() == 0);
126+
127+
// 3. 빈 힙 top 예외
128+
bool exceptionThrown = false;
129+
130+
try {
131+
heap.top();
132+
} catch (const std::out_of_range&) {
133+
exceptionThrown = true;
134+
}
135+
136+
assert(exceptionThrown);
137+
138+
// 4. 첫 push
139+
heap.push(30);
140+
141+
assert(!heap.empty());
142+
assert(heap.size() == 1);
143+
assert(heap.capacity() == 1);
144+
assert(heap.top() == 30);
145+
146+
// 5. siftUp 확인
147+
heap.push(20);
148+
149+
assert(heap.size() == 2);
150+
assert(heap.capacity() == 2);
151+
assert(heap.top() == 20);
152+
153+
heap.push(10);
154+
155+
assert(heap.size() == 3);
156+
assert(heap.capacity() == 4);
157+
assert(heap.top() == 10);
158+
159+
heap.push(40);
160+
heap.push(5);
161+
162+
assert(heap.size() == 5);
163+
assert(heap.capacity() == 8);
164+
assert(heap.top() == 5);
165+
166+
// 현재 값:
167+
// 30, 20, 10, 40, 5
168+
// 최소 힙 top은 5
169+
170+
// 6. 중복값 삽입
171+
heap.push(5);
172+
heap.push(10);
173+
174+
assert(heap.size() == 7);
175+
assert(heap.top() == 5);
176+
177+
// 7. top 참조 반환 확인
178+
// 주의: top 값을 직접 수정하면 힙 조건이 깨질 수 있음
179+
int& topRef = heap.top();
180+
assert(topRef == 5);
181+
182+
// 8. pop 순서 확인
183+
int expected1[] = {5, 5, 10, 10, 20, 30, 40};
184+
185+
for (int value : expected1) {
186+
assert(!heap.empty());
187+
assert(heap.top() == value);
188+
heap.pop();
189+
}
190+
191+
assert(heap.empty());
192+
assert(heap.size() == 0);
193+
assert(heap.capacity() == 8);
194+
195+
// 9. pop 이후 재사용
196+
heap.push(100);
197+
heap.push(50);
198+
heap.push(75);
199+
heap.push(25);
200+
201+
assert(heap.size() == 4);
202+
assert(heap.top() == 25);
203+
204+
int expected2[] = {25, 50, 75, 100};
205+
206+
for (int value : expected2) {
207+
assert(heap.top() == value);
208+
heap.pop();
209+
}
210+
211+
assert(heap.empty());
212+
213+
// 10. reserve 직접 호출
214+
heap.reserve(20);
215+
216+
assert(heap.capacity() == 20);
217+
assert(heap.size() == 0);
218+
219+
heap.push(8);
220+
heap.push(3);
221+
heap.push(6);
222+
heap.push(1);
223+
heap.push(7);
224+
225+
assert(heap.size() == 5);
226+
assert(heap.capacity() == 20);
227+
assert(heap.top() == 1);
228+
229+
// 작은 reserve는 무시
230+
heap.reserve(10);
231+
232+
assert(heap.capacity() == 20);
233+
assert(heap.size() == 5);
234+
assert(heap.top() == 1);
235+
236+
// 같은 capacity도 무시
237+
heap.reserve(20);
238+
239+
assert(heap.capacity() == 20);
240+
assert(heap.size() == 5);
241+
242+
// 11. clear
243+
int previousCapacity = heap.capacity();
244+
245+
heap.clear();
246+
247+
assert(heap.empty());
248+
assert(heap.size() == 0);
249+
assert(heap.capacity() == previousCapacity);
250+
251+
// clear 후 재사용
252+
heap.push(4);
253+
heap.push(2);
254+
heap.push(9);
255+
heap.push(1);
256+
257+
assert(heap.size() == 4);
258+
assert(heap.top() == 1);
259+
assert(heap.capacity() == previousCapacity);
260+
261+
// 12. 오름차순 pop 검증
262+
int expected3[] = {1, 2, 4, 9};
263+
264+
for (int value : expected3) {
265+
assert(heap.top() == value);
266+
heap.pop();
267+
}
268+
269+
assert(heap.empty());
270+
271+
// 13. 내림차순 삽입
272+
for (int i = 100; i >= 1; i--) {
273+
heap.push(i);
274+
}
275+
276+
assert(heap.size() == 100);
277+
assert(heap.top() == 1);
278+
279+
for (int expected = 1; expected <= 100; expected++) {
280+
assert(heap.top() == expected);
281+
heap.pop();
282+
}
283+
284+
assert(heap.empty());
285+
assert(heap.size() == 0);
286+
287+
// 14. 오름차순 삽입
288+
for (int i = 1; i <= 100; i++) {
289+
heap.push(i);
290+
}
291+
292+
assert(heap.size() == 100);
293+
assert(heap.top() == 1);
294+
295+
for (int expected = 1; expected <= 100; expected++) {
296+
assert(heap.top() == expected);
297+
heap.pop();
298+
}
299+
300+
assert(heap.empty());
301+
302+
// 15. 음수와 중복값
303+
int values[] = {
304+
0, -10, 5, -3, -10, 8, 2, -1
305+
};
306+
307+
for (int value : values) {
308+
heap.push(value);
309+
}
310+
311+
int expected4[] = {
312+
-10, -10, -3, -1, 0, 2, 5, 8
313+
};
314+
315+
for (int value : expected4) {
316+
assert(heap.top() == value);
317+
heap.pop();
318+
}
319+
320+
assert(heap.empty());
321+
322+
// 16. 원소 하나에서 pop
323+
heap.push(42);
324+
325+
assert(heap.size() == 1);
326+
assert(heap.top() == 42);
327+
328+
heap.pop();
329+
330+
assert(heap.empty());
331+
assert(heap.size() == 0);
332+
333+
// 빈 상태에서 여러 번 pop
334+
heap.pop();
335+
heap.pop();
336+
337+
assert(heap.empty());
338+
339+
cout << "ALL TESTS PASSED\n";
340+
341+
return 0;
342+
}

0 commit comments

Comments
 (0)