1 /********************* */
4 ** Top contributors (to current version):
5 ** Tim King, Morgan Deters, Mathias Preiner
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
8 ** in the top-level source directory and their institutional affiliations.
9 ** All rights reserved. See the file COPYING in the top-level source
10 ** directory for licensing information.\endverbatim
12 ** \brief An implementation of a binary heap
14 ** An implementation of a binary heap.
15 ** Attempts to roughly follow the contract of Boost's d_ary_heap.
16 ** (http://www.boost.org/doc/libs/1_49_0/doc/html/boost/heap/d_ary_heap.html)
17 ** Also attempts to generalize ext/pd_bs/priority_queue.
18 ** (http://gcc.gnu.org/onlinedocs/libstdc++/ext/pb_ds/priority_queue.html)
21 #include "cvc4_private.h"
23 #ifndef CVC4__BIN_HEAP_H
24 #define CVC4__BIN_HEAP_H
29 #include "base/check.h"
30 #include "base/exception.h"
35 * BinaryHeap that orders its elements greatest-first (i.e., in the opposite
36 * direction of the provided comparator). Update of elements is permitted
37 * via handles, which are not invalidated by mutation (pushes and pops etc.).
38 * Handles are invalidted when their element is no longer a member of the
39 * heap. Iteration over elements is supported but iteration is unsorted and
40 * iterators are immutable.
42 template <class Elem
, class CmpFcn
= std::less
<Elem
> >
48 typedef std::vector
<HElement
*> ElementVector
;
51 HElement(size_t pos
, const T
& elem
): d_pos(pos
), d_elem(elem
) {}
54 };/* struct HElement */
56 /** A 0 indexed binary heap. */
59 /** The comparator. */
62 // disallow copy and assignment
63 BinaryHeap(const BinaryHeap
&) = delete;
64 BinaryHeap
& operator=(const BinaryHeap
&) = delete;
67 BinaryHeap(const CmpFcn
& c
= CmpFcn())
79 handle(HElement
* p
) : d_pointer(p
){}
80 friend class BinaryHeap
;
82 handle() : d_pointer(NULL
) {}
83 const T
& operator*() const {
84 Assert(d_pointer
!= NULL
);
85 return d_pointer
->d_elem
;
88 bool operator==(const handle
& h
) const {
89 return d_pointer
== h
.d_pointer
;
92 bool operator!=(const handle
& h
) const {
93 return d_pointer
!= h
.d_pointer
;
96 }; /* BinaryHeap<>::handle */
98 class const_iterator
: public std::iterator
<std::input_iterator_tag
, Elem
> {
100 typename
ElementVector::const_iterator d_iter
;
101 friend class BinaryHeap
;
102 const_iterator(const typename
ElementVector::const_iterator
& iter
)
107 inline bool operator==(const const_iterator
& ci
) const{
108 return d_iter
== ci
.d_iter
;
110 inline bool operator!=(const const_iterator
& ci
) const{
111 return d_iter
!= ci
.d_iter
;
113 inline const_iterator
& operator++(){
117 inline const_iterator
operator++(int){
118 const_iterator i
= *this;
122 inline const T
& operator*() const{
123 const HElement
* he
= *d_iter
;
127 };/* BinaryHeap<>::const_iterator */
129 typedef const_iterator iterator
;
131 inline size_t size() const { return d_heap
.size(); }
132 inline bool empty() const { return d_heap
.empty(); }
134 inline const_iterator
begin() const {
135 return const_iterator(d_heap
.begin());
138 inline const_iterator
end() const {
139 return const_iterator(d_heap
.end());
143 typename
ElementVector::iterator i
=d_heap
.begin(), iend
=d_heap
.end();
151 void swap(BinaryHeap
& heap
){
152 std::swap(d_heap
, heap
.d_heap
);
153 std::swap(d_cmp
, heap
.d_cmp
);
156 handle
push(const T
& toAdded
){
157 Assert(size() < MAX_SIZE
);
158 HElement
* he
= new HElement(size(), toAdded
);
159 d_heap
.push_back(he
);
164 void erase(handle h
){
166 Assert(debugHandle(h
));
168 HElement
* he
= h
.d_pointer
;
169 size_t pos
= he
->d_pos
;
171 // the top element can be efficiently removed by pop
173 }else if(pos
== last()){
174 // the last element can be safely removed
178 // This corresponds to
179 // 1) swapping the elements at pos with the element at last:
180 // 2) deleting the new last element
181 // 3) updating the position of the new element at pos
182 swapIndices(pos
, last());
185 update(handle(d_heap
[pos
]));
191 swapIndices(root(), last());
192 HElement
* b
= d_heap
.back();
197 down_heap(d_heap
.front());
201 const T
& top() const {
203 return (d_heap
.front())->d_elem
;
207 void update(handle h
){
209 Assert(debugHandle(h
));
211 // The relationship between h and its parent, left and right has become unknown.
212 // But it is assumed that parent <= left, and parent <= right still hold.
213 // Figure out whether to up_heap or down_heap.
216 HElement
* he
= h
.d_pointer
;
218 size_t pos
= he
->d_pos
;
223 size_t par
= parent(pos
);
224 HElement
* at_parent
= d_heap
[par
];
225 if(gt(he
->d_elem
, at_parent
->d_elem
)){
235 void update(handle h
, const T
& val
){
237 Assert(debugHandle(h
));
238 h
.d_pointer
->d_elem
= val
;
242 /** (std::numeric_limits<size_t>::max()-2)/2; */
243 static const size_t MAX_SIZE
;
246 inline bool gt(const T
& a
, const T
& b
) const{
247 // cmp acts like an operator<
251 inline bool lt(const T
& a
, const T
& b
) const{
255 inline static size_t parent(size_t p
){
259 inline static size_t right(size_t p
){ return 2*p
+2; }
260 inline static size_t left(size_t p
){ return 2*p
+1; }
261 inline static size_t root(){ return 0; }
262 inline size_t last() const{
267 inline void swapIndices(size_t i
, size_t j
){
268 HElement
* at_i
= d_heap
[i
];
269 HElement
* at_j
= d_heap
[j
];
273 inline void swapPointers(HElement
* at_i
, HElement
* at_j
){
274 // still works if at_i == at_j
275 size_t i
= at_i
->d_pos
;
276 size_t j
= at_j
->d_pos
;
280 inline void swap(size_t i
, size_t j
, HElement
* at_i
, HElement
* at_j
){
281 // still works if i == j
282 Assert(i
== at_i
->d_pos
);
283 Assert(j
== at_j
->d_pos
);
290 void up_heap(HElement
* he
){
291 const size_t& curr
= he
->d_pos
;
292 // The value of curr changes implicitly during swap operations.
293 while(curr
!= root()){
294 // he->d_elem > parent
295 size_t par
= parent(curr
);
296 HElement
* at_parent
= d_heap
[par
];
297 if(gt(he
->d_elem
, at_parent
->d_elem
)){
298 swap(curr
, par
, he
, at_parent
);
305 void down_heap(HElement
* he
){
306 const size_t& curr
= he
->d_pos
;
307 // The value of curr changes implicitly during swap operations.
311 while((r
= right(curr
)) < N
){
314 // if at_left == at_right, favor left
315 HElement
* at_left
= d_heap
[l
];
316 HElement
* at_right
= d_heap
[r
];
317 if(lt(he
->d_elem
, at_left
->d_elem
)){
319 if(lt(at_left
->d_elem
, at_right
->d_elem
)){
320 // he < at_left < at_right
321 swap(curr
, r
, he
, at_right
);
324 // at_right <= at_left
325 swap(curr
, l
, he
, at_left
);
329 if(lt(he
->d_elem
, at_right
->d_elem
)){
330 // at_left <= he < at_right
331 swap(curr
, r
, he
, at_right
);
341 // there is a left but not a right
342 HElement
* at_left
= d_heap
[l
];
343 if(lt(he
->d_elem
, at_left
->d_elem
)){
345 swap(curr
, l
, he
, at_left
);
350 bool debugHandle(handle h
) const{
351 HElement
* he
= h
.d_pointer
;
354 }else if(he
->d_pos
>= size()){
357 return he
== d_heap
[he
->d_pos
];
361 }; /* class BinaryHeap<> */
363 template <class Elem
, class CmpFcn
>
364 const size_t BinaryHeap
<Elem
,CmpFcn
>::MAX_SIZE
= (std::numeric_limits
<size_t>::max()-2)/2;
368 #endif /* CVC4__BIN_HEAP_H */