-
Notifications
You must be signed in to change notification settings - Fork 7
/
heap_select.h
106 lines (87 loc) · 2.91 KB
/
heap_select.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
/* Copyright Danila Kutenin, 2020-.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* https://boost.org/LICENSE_1_0.txt)
*/
#pragma once
#include <algorithm>
#include <functional>
#include <iterator>
#include <type_traits>
#include <utility>
namespace miniselect {
namespace heap_select_detail {
template <class Compare>
struct CompareRefType {
// Pass the comparator by lvalue reference. Or in debug mode, using a
// debugging wrapper that stores a reference.
using type = typename std::add_lvalue_reference<Compare>::type;
};
template <class Compare, class Iter>
inline void sift_down(Iter first, Compare comp,
typename std::iterator_traits<Iter>::difference_type len,
Iter start) {
using difference_type = typename std::iterator_traits<Iter>::difference_type;
using value_type = typename std::iterator_traits<Iter>::value_type;
difference_type child = start - first;
if (len < 2 || (len - 2) / 2 < child) return;
child = 2 * child + 1;
Iter child_i = first + child;
if ((child + 1) < len && comp(*child_i, *(child_i + 1))) {
++child_i;
++child;
}
if (comp(*child_i, *start)) {
return;
}
value_type top(std::move(*start));
do {
*start = std::move(*child_i);
start = child_i;
if ((len - 2) / 2 < child) {
break;
}
child = 2 * child + 1;
child_i = first + child;
if ((child + 1) < len && comp(*child_i, *(child_i + 1))) {
++child_i;
++child;
}
} while (!comp(*child_i, top));
*start = std::move(top);
}
template <class Compare, class Iter>
inline void heap_select_loop(Iter first, Iter middle, Iter last, Compare comp) {
std::make_heap(first, middle, comp);
typename std::iterator_traits<Iter>::difference_type len = middle - first;
for (Iter i = middle; i != last; ++i) {
if (comp(*i, *first)) {
std::swap(*i, *first);
sift_down<Compare>(first, comp, len, first);
}
}
}
} // namespace heap_select_detail
template <class Iter, class Compare>
inline void heap_select(Iter first, Iter middle, Iter end, Compare comp) {
if (middle == end) return;
heap_select_detail::heap_select_loop(first, middle + 1, end, comp);
std::swap(*first, *middle);
}
template <class Iter>
inline void heap_select(Iter first, Iter middle, Iter end) {
heap_select(first, middle, end,
std::less<typename std::iterator_traits<Iter>::value_type>());
}
template <class Iter, class Compare>
inline void heap_partial_sort(Iter first, Iter middle, Iter end, Compare comp) {
heap_select_detail::heap_select_loop(first, middle, end, comp);
std::sort_heap(first, middle, comp);
}
template <class Iter>
inline void heap_partial_sort(Iter first, Iter middle, Iter end) {
heap_partial_sort(
first, middle, end,
std::less<typename std::iterator_traits<Iter>::value_type>());
}
} // namespace miniselect