-
Notifications
You must be signed in to change notification settings - Fork 160
/
heap.cpp
137 lines (123 loc) · 4.22 KB
/
heap.cpp
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
/* First learn how binary heaps work, and how they can efficiently implement
* Dijkstra more efficiently than BST:
* https://stackoverflow.com/questions/6147242/heap-vs-binary-search-tree-bst/29548834#29548834
*
* There are two ways to make priority queues in C++:
*
* - `make_heap` and other functions in the family, which implement a heap
* on top of a random access container, typically std::vector.
*
* - `priority_queue` class, which seems to just use `std::vector` + `make_heap` by default
* internally: https://stackoverflow.com/questions/11266360/when-should-i-use-make-heap-vs-priority-queue
*/
#include "common.hpp"
int main() {
int myints[]{10, 20, 30, 5, 15};
std::vector<int> v(myints, myints + 5);
// Heap functions.
{
/* # make_heap
*
* Make random access data structure into a heap.
*/
{
std::make_heap(v.begin(), v.end());
assert(v.front() == 30);
}
/* # pop_heap
*
* Remove the largest element from the heap.
*
* That element is moved to the end of the data structure, but since the
* heap should have its length reduced by one, the element is effectively removed.
*
* Assumes that the input range is already a heap, made with `make_heap` for example.
*/
{
std::pop_heap(v.begin(), v.end());
// The element still exists on the data structure.
assert(v.back() == 30);
// The second largest element hat become the largest.
assert(v.front() == 20);
// Remove the element from the data structure definitively
v.pop_back();
}
/* # push_heap
*
* Insert element into a heap.
*
* Assumes that:
*
* - the range 0 - (end - 1) was already a heap
* - the new element to be inserted into that heap is at end.
*/
{
// Add the new element to the data structure.
v.push_back(99);
// Reorganize the data so that the last element will be placed in the heap.
std::push_heap(v.begin(), v.end());
assert(v.front() == 99);
}
/* # sort_heap
*
* Assumes that the input range is a heap, and sorts it in increasing order.
*
* The assumption that we have a heap allows for $O(ln)$ sorting,
* much faster than the optimal bound $O(n log n)$.
*
* This is exactly what the heapsort algorithm does: make_heap and then sort_heap.
*/
{
std::sort_heap(v.begin(), v.end());
//assert(v)
//v == 5 10 15 20 99
}
}
/* # priority_queue
*
* It could however use some other implementation in theory, and it does seem that GCC libstdc++ does provide
* a few alternatives with the policy base
*
* No Fibonacci as of 7.3.0 however:
*
* - https://gcc.gnu.org/onlinedocs/gcc-7.3.0/libstdc++/manual/manual/policy_based_data_structures_test.html#performance.priority_queue
* - http://stackoverflow.com/questions/14118367/stl-for-fibonacci-heap
*
* TODO As of C++11, does not support the increase key operation.
*
* Boost offers explicit heap types: Fibonacci, binary and others.
*/
{
// max
{
std::priority_queue<int> q;
for(int n : {1,8,5,6,3,4,0,9,7,2})
q.push(n);
assert(q.top() == 9);
q.pop();
assert(q.top() == 8);
q.pop();
assert(q.top() == 7);
q.pop();
}
// min
{
std::priority_queue<int, std::vector<int>, std::greater<int>> q;
for(int n : {1,8,5,6,3,4,0,9,7,2})
q.push(n);
assert(q.top() == 0);
q.pop();
assert(q.top() == 1);
q.pop();
assert(q.top() == 2);
q.pop();
}
// Dupes are accepted unlike in sets.
{
std::priority_queue<int, std::vector<int>, std::greater<int>> q;
q.push(1);
q.push(1);
assert(q.size() == 2);
}
}
}