-
Notifications
You must be signed in to change notification settings - Fork 20
/
make-heap.h
135 lines (115 loc) · 3.78 KB
/
make-heap.h
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
#pragma once
#include <utility>
namespace scratch::detail {
template<class RandomIt, class Diff, class Compare>
void sift_downward(RandomIt first, Diff current_index, Diff last_index, Compare less)
{
using std::swap;
while (current_index < last_index) {
RandomIt current = first + current_index;
Diff left_child_index = (2 * current_index) + 1;
Diff right_child_index = (2 * current_index) + 2;
if (right_child_index < last_index) {
RandomIt left_child = first + left_child_index;
RandomIt right_child = first + right_child_index;
Diff min_child_index = less(*left_child, *right_child) ? left_child_index : right_child_index;
RandomIt min_child = first + min_child_index;
if (less(*min_child, *current)) {
swap(*current, *min_child);
current_index = min_child_index;
} else {
return;
}
} else if (left_child_index < last_index) {
Diff min_child_index = left_child_index;
RandomIt min_child = first + left_child_index;
if (less(*min_child, *current)) {
swap(*current, *min_child);
current_index = min_child_index;
} else {
return;
}
} else {
return;
}
}
}
template<class RandomIt, class Diff, class Compare>
void sift_upward(RandomIt first, Diff current_index, Compare less)
{
using std::swap;
while (current_index) {
RandomIt current = first + current_index;
Diff parent_index = (current_index - 1) / 2;
RandomIt parent = first + parent_index;
if (less(*current, *parent)) {
swap(*current, *parent);
current_index = parent_index;
} else {
return;
}
}
}
} // namespace scratch::detail
namespace scratch {
template<class RandomIt, class Compare>
void make_heap(RandomIt first, RandomIt last, Compare less)
{
auto last_index = (last - first);
// We could build the heap "top-down", by sifting each element [0..n) upward.
// But libc++ observes that it is faster to build it "bottom-up", by assuming that
// elements [n/2 .. n) are already in plausible spots, and then sifting each element (n/2 .. 0] downward!
auto current_index = (last_index / 2);
while (current_index) {
--current_index;
detail::sift_downward(first, current_index, last_index, less);
}
}
template<class RandomIt, class Compare>
void push_heap(RandomIt first, RandomIt last, Compare less)
{
// TODO
auto last_index = (last - first);
--last_index;
detail::sift_upward(first, last_index, less);
}
template<class RandomIt, class Compare>
void pop_heap(RandomIt first, RandomIt last, Compare less)
{
auto last_index = (last - first);
--last_index;
if (last_index) {
using std::swap;
swap(*first, *(first + last_index));
detail::sift_downward(first, 0, last_index, less);
}
}
template<class RandomIt, class Compare>
void sort_heap(RandomIt first, RandomIt last, Compare less)
{
while (first != last) {
scratch::pop_heap(first, last, less);
--last;
}
}
template<class RandomIt>
void make_heap(RandomIt first, RandomIt last)
{
make_heap(first, last, [](auto&& a, auto&& b){ return a < b; });
}
template<class RandomIt>
void push_heap(RandomIt first, RandomIt last)
{
push_heap(first, last, [](auto&& a, auto&& b){ return a < b; });
}
template<class RandomIt>
void pop_heap(RandomIt first, RandomIt last)
{
pop_heap(first, last, [](auto&& a, auto&& b){ return a < b; });
}
template<class RandomIt>`
void sort_heap(RandomIt first, RandomIt last)
{
sort_heap(first, last, [](auto&& a, auto&& b){ return a < b; });
}
} // namespace scratch