@@ -38,7 +38,7 @@ class PairingHeap;
38
38
39
39
40
40
template <typename T, typename compare = std::less<T>>
41
- class PairingHeapNode : public std ::enable_shared_from_this<PairingHeapNode<T, compare>> {
41
+ class PairingHeapNode {
42
42
public:
43
43
using this_type = PairingHeapNode<T, compare>;
44
44
@@ -47,7 +47,6 @@ class PairingHeapNode : public std::enable_shared_from_this<PairingHeapNode<T, c
47
47
T data;
48
48
compare cmp;
49
49
50
- public:
51
50
PairingHeapNode (const T &data) :
52
51
data{data} {}
53
52
@@ -56,6 +55,10 @@ class PairingHeapNode : public std::enable_shared_from_this<PairingHeapNode<T, c
56
55
57
56
~PairingHeapNode () = default ;
58
57
58
+ PairingHeapNode (const this_type &other) = delete ;
59
+
60
+ this_type &operator =(const this_type &other) = delete ;
61
+
59
62
/* *
60
63
* Get contained node data.
61
64
*/
@@ -66,14 +69,14 @@ class PairingHeapNode : public std::enable_shared_from_this<PairingHeapNode<T, c
66
69
/* *
67
70
* Let this node become a child of the given one.
68
71
*/
69
- void become_child_of (const std::shared_ptr< this_type> & node) {
70
- node->add_child (this -> shared_from_this () );
72
+ void become_child_of (this_type * const node) {
73
+ node->add_child (this );
71
74
}
72
75
73
76
/* *
74
77
* Add the given node as a child to this one.
75
78
*/
76
- void add_child (const std::shared_ptr< this_type> & new_child) {
79
+ void add_child (this_type * const new_child) {
77
80
// first child is the most recently attached one
78
81
// it must not have siblings as they will get lost.
79
82
@@ -85,31 +88,31 @@ class PairingHeapNode : public std::enable_shared_from_this<PairingHeapNode<T, c
85
88
}
86
89
87
90
this ->first_child = new_child;
88
- new_child->parent = this -> shared_from_this () ;
91
+ new_child->parent = this ;
89
92
}
90
93
91
94
/* *
92
95
* This method decides which node becomes the new root node
93
96
* by comparing `this` with `node`.
94
97
* The new root is returned, it has the other node as child.
95
98
*/
96
- std::shared_ptr< this_type> link_with (const std::shared_ptr< this_type> & node) {
97
- std::shared_ptr< this_type> new_root;
98
- std::shared_ptr< this_type> new_child;
99
+ this_type * link_with (this_type * const node) {
100
+ this_type * new_root;
101
+ this_type * new_child;
99
102
100
103
if (this ->cmp (this ->data , node->data )) {
101
- new_root = this -> shared_from_this () ;
104
+ new_root = this ;
102
105
new_child = node;
103
106
}
104
107
else {
105
108
new_root = node;
106
- new_child = this -> shared_from_this () ;
109
+ new_child = this ;
107
110
}
108
111
109
112
// children of new root become siblings of new new_child
110
113
// -> parent of new child = new root
111
114
112
- // this whll be set by the add_child method
115
+ // this will be set by the add_child method
113
116
new_child->prev_sibling = nullptr ;
114
117
new_child->next_sibling = nullptr ;
115
118
@@ -128,15 +131,15 @@ class PairingHeapNode : public std::enable_shared_from_this<PairingHeapNode<T, c
128
131
* Recursive call, one stage for each all childs of the root node.
129
132
* This results in the computation of the new subtree root.
130
133
*/
131
- std::shared_ptr< this_type> link_backwards () {
134
+ this_type * link_backwards () {
132
135
if (this ->next_sibling == nullptr ) {
133
136
// reached end, return this as current root,
134
137
// the previous siblings will be linked to it.
135
- return this -> shared_from_this () ;
138
+ return this ;
136
139
}
137
140
138
141
// recurse to last sibling,
139
- std::shared_ptr< this_type> node = this ->next_sibling ->link_backwards ();
142
+ this_type * node = this ->next_sibling ->link_backwards ();
140
143
141
144
// then link ourself to the new root.
142
145
this ->next_sibling = nullptr ;
@@ -153,9 +156,9 @@ class PairingHeapNode : public std::enable_shared_from_this<PairingHeapNode<T, c
153
156
*/
154
157
void loosen () {
155
158
// release us from some other node
156
- if (this ->parent and this ->parent ->first_child == this -> shared_from_this () ) {
157
- // we are the first child
158
- // make the next sibling the first child
159
+ if (this ->parent and this ->parent ->first_child == this ) {
160
+ // we are child
161
+ // make the next sibling child
159
162
this ->parent ->first_child = this ->next_sibling ;
160
163
}
161
164
// if we have a previous sibling
@@ -176,10 +179,10 @@ class PairingHeapNode : public std::enable_shared_from_this<PairingHeapNode<T, c
176
179
}
177
180
178
181
private:
179
- std::shared_ptr< this_type> first_child;
180
- std::shared_ptr< this_type> prev_sibling;
181
- std::shared_ptr< this_type> next_sibling;
182
- std::shared_ptr< this_type> parent; // for decrease-key and delete
182
+ this_type * first_child = nullptr ;
183
+ this_type * prev_sibling = nullptr ;
184
+ this_type * next_sibling = nullptr ;
185
+ this_type * parent = nullptr ; // for decrease-key and delete
183
186
};
184
187
185
188
@@ -191,10 +194,8 @@ template <typename T,
191
194
typename heapnode_t = PairingHeapNode<T, compare>>
192
195
class PairingHeap final {
193
196
public:
194
- using node_t = heapnode_t ;
195
- using element_t = std::shared_ptr<node_t >;
196
- using this_type = PairingHeap<T, compare, node_t >;
197
- using cmp_t = compare;
197
+ using element_t = heapnode_t *;
198
+ using this_type = PairingHeap<T, compare, heapnode_t >;
198
199
199
200
/* *
200
201
* create a empty heap.
@@ -204,14 +205,16 @@ class PairingHeap final {
204
205
root_node (nullptr ) {
205
206
}
206
207
207
- ~PairingHeap () = default ;
208
+ ~PairingHeap () {
209
+ this ->clear ();
210
+ };
208
211
209
212
/* *
210
213
* adds the given item to the heap.
211
214
* O(1)
212
215
*/
213
216
element_t push (const T &item) {
214
- element_t new_node = std::make_shared< node_t > (item);
217
+ element_t new_node = new heapnode_t (item);
215
218
this ->push_node (new_node);
216
219
return new_node;
217
220
}
@@ -221,25 +224,18 @@ class PairingHeap final {
221
224
* O(1)
222
225
*/
223
226
element_t push (T &&item) {
224
- element_t new_node = std::make_shared< node_t > (std::move (item));
227
+ element_t new_node = new heapnode_t (std::move (item));
225
228
this ->push_node (new_node);
226
229
return new_node;
227
230
}
228
231
229
- /* *
230
- * returns and removes the smallest item on the heap.
231
- */
232
- T pop () {
233
- return std::move (this ->pop_node ()->data );
234
- }
235
-
236
232
/* *
237
233
* returns the smallest item on the heap and deletes it.
238
234
* also known as delete_min.
239
235
* _________
240
236
* Ω(log log n), O(2^(2*√log log n'))
241
237
*/
242
- element_t pop_node () {
238
+ T pop () {
243
239
if (this ->root_node == nullptr ) {
244
240
throw Error{MSG (err) << " Can't pop an empty heap!" };
245
241
}
@@ -316,36 +312,9 @@ class PairingHeap final {
316
312
ret->first_child = nullptr ;
317
313
318
314
// and it's done!
319
- return ret;
320
- }
321
-
322
- /* *
323
- * Unlink a node from the heap.
324
- *
325
- * If the item is the current root, just pop().
326
- * else, cut the node from its parent, pop() that subtree
327
- * and merge these trees.
328
- *
329
- * O(pop_node)
330
- */
331
- void unlink_node (const element_t &node) {
332
- if (node == this ->root_node ) {
333
- this ->pop_node ();
334
- }
335
- else {
336
- node->loosen ();
337
-
338
- element_t real_root = this ->root_node ;
339
- this ->root_node = node;
340
- this ->pop_node ();
341
-
342
- element_t new_root = this ->root_node ;
343
- this ->root_node = real_root;
344
-
345
- if (new_root != nullptr ) {
346
- this ->root_insert (new_root);
347
- }
348
- }
315
+ T data = std::move (ret->data );
316
+ delete ret;
317
+ return data;
349
318
}
350
319
351
320
/* *
@@ -391,21 +360,52 @@ class PairingHeap final {
391
360
*
392
361
* O(1) (but slower than decrease), and O(pop) when node is the root.
393
362
*/
394
- void update (const element_t &node) {
363
+ void update (element_t &node) {
395
364
if (node != this ->root_node ) [[likely]] {
396
- this ->unlink_node (node);
397
- this ->push_node (node);
365
+ node = this ->push (this ->remove_node (node));
398
366
}
399
367
else {
400
368
// it's the root node, so we just pop and push it.
401
- this ->push_node (this ->pop_node ());
369
+ node = this ->push (this ->pop ());
370
+ }
371
+ }
372
+
373
+ /* *
374
+ * remove a node from the heap. Return its data.
375
+ *
376
+ * If the item is the current root, just pop().
377
+ * else, cut the node from its parent, pop() that subtree
378
+ * and merge these trees.
379
+ *
380
+ * O(pop_node)
381
+ */
382
+ T remove_node (const element_t &node) {
383
+ if (node == this ->root_node ) {
384
+ return this ->pop ();
385
+ }
386
+ else {
387
+ node->loosen ();
388
+
389
+ element_t real_root = this ->root_node ;
390
+ this ->root_node = node;
391
+ T data = this ->pop ();
392
+
393
+ element_t new_root = this ->root_node ;
394
+ this ->root_node = real_root;
395
+
396
+ if (new_root != nullptr ) {
397
+ this ->root_insert (new_root);
398
+ }
399
+ return data;
402
400
}
403
401
}
404
402
405
403
/* *
406
404
* erase all elements on the heap.
407
405
*/
408
406
void clear () {
407
+ auto delete_node = [](element_t node) { delete node; };
408
+ this ->iter_all <true >(delete_node);
409
409
this ->root_node = nullptr ;
410
410
this ->node_count = 0 ;
411
411
#if OPENAGE_PAIRINGHEAP_DEBUG
@@ -579,39 +579,59 @@ class PairingHeap final {
579
579
}
580
580
#endif
581
581
582
+ /* *
583
+ * Apply the given function to all nodes in the tree.
584
+ *
585
+ * @tparam reverse If true, the function is applied to the nodes in reverse order.
586
+ * @param func Function to apply to each node.
587
+ */
588
+ template <bool reverse = false >
582
589
void iter_all (const std::function<void (const element_t &)> &func) const {
583
- this ->walk_tree (this ->root_node , func);
590
+ this ->walk_tree <reverse> (this ->root_node , func);
584
591
}
585
592
586
- protected:
587
- void walk_tree (const element_t &root,
593
+ private:
594
+ /* *
595
+ * Apply the given function to all nodes in the tree.
596
+ *
597
+ * @tparam reverse If true, the function is applied to the nodes in reverse order.
598
+ * @param start Starting node.
599
+ * @param func Function to apply to each node.
600
+ */
601
+ template <bool reverse = false >
602
+ void walk_tree (const element_t &start,
588
603
const std::function<void (const element_t &)> &func) const {
589
- func (root);
604
+ if constexpr (not reverse) {
605
+ func (start);
606
+ }
590
607
591
- if (root ) {
592
- auto node = root ->first_child ;
608
+ if (start ) {
609
+ auto node = start ->first_child ;
593
610
while (true ) {
594
611
if (not node) {
595
612
break ;
596
613
}
597
614
598
- this ->walk_tree (node, func);
615
+ this ->walk_tree <reverse> (node, func);
599
616
node = node->next_sibling ;
600
617
}
618
+ if constexpr (reverse) {
619
+ func (start);
620
+ }
601
621
}
602
622
}
603
623
624
+
604
625
/* *
605
626
* adds the given node to the heap.
606
627
* use this if the node was not in the heap before.
607
628
* O(1)
608
629
*/
609
630
void push_node (const element_t &node) {
610
631
this ->root_insert (node);
611
-
612
632
#if OPENAGE_PAIRINGHEAP_DEBUG
613
- auto ins = this ->nodes .insert (node);
614
- if (not ins. second ) {
633
+ auto [iter, result] = this ->nodes .insert (node);
634
+ if (not result ) {
615
635
throw Error{ERR << " node already known" };
616
636
}
617
637
#endif
@@ -631,7 +651,6 @@ class PairingHeap final {
631
651
}
632
652
}
633
653
634
- protected:
635
654
compare cmp;
636
655
size_t node_count;
637
656
element_t root_node;
0 commit comments