@@ -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,31 +224,30 @@ 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
}
246
242
247
243
// 0. remove tree root, it's the minimum.
248
244
element_t ret = this ->root_node ;
245
+
246
+ if (!this ->nodes .erase (ret)) {
247
+ throw Error{MSG (err) << " didn't remove node" };
248
+ }
249
+
250
+ this ->node_count -= 1 ;
249
251
element_t current_sibling = this ->root_node ->first_child ;
250
252
this ->root_node = nullptr ;
251
253
@@ -303,49 +305,14 @@ class PairingHeap final {
303
305
this ->root_node = first_pair->link_backwards ();
304
306
}
305
307
306
- this ->node_count -= 1 ;
307
-
308
- #if OPENAGE_PAIRINGHEAP_DEBUG
309
- if (1 != this ->nodes .erase (ret)) {
310
- throw Error{ERR << " didn't remove node" };
311
- }
312
- #endif
313
-
314
308
// (to find those two lines, 14h of debugging passed)
315
309
ret->loosen ();
316
310
ret->first_child = nullptr ;
317
311
318
312
// 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
- }
313
+ T data = std::move (ret->data );
314
+ delete ret;
315
+ return data;
349
316
}
350
317
351
318
/* *
@@ -391,14 +358,43 @@ class PairingHeap final {
391
358
*
392
359
* O(1) (but slower than decrease), and O(pop) when node is the root.
393
360
*/
394
- void update (const element_t &node) {
361
+ void update (element_t &node) {
395
362
if (node != this ->root_node ) [[likely]] {
396
- this ->unlink_node (node);
397
- this ->push_node (node);
363
+ node = this ->push (this ->remove_node (node));
398
364
}
399
365
else {
400
366
// it's the root node, so we just pop and push it.
401
- this ->push_node (this ->pop_node ());
367
+ node = this ->push (this ->pop ());
368
+ }
369
+ }
370
+
371
+ /* *
372
+ * remove a node from the heap. Return its data.
373
+ *
374
+ * If the item is the current root, just pop().
375
+ * else, cut the node from its parent, pop() that subtree
376
+ * and merge these trees.
377
+ *
378
+ * O(pop_node)
379
+ */
380
+ T remove_node (const element_t &node) {
381
+ if (node == this ->root_node ) {
382
+ return this ->pop ();
383
+ }
384
+ else {
385
+ node->loosen ();
386
+
387
+ element_t real_root = this ->root_node ;
388
+ this ->root_node = node;
389
+ T data = this ->pop ();
390
+
391
+ element_t new_root = this ->root_node ;
392
+ this ->root_node = real_root;
393
+
394
+ if (new_root != nullptr ) {
395
+ this ->root_insert (new_root);
396
+ }
397
+ return data;
402
398
}
403
399
}
404
400
@@ -408,9 +404,10 @@ class PairingHeap final {
408
404
void clear () {
409
405
this ->root_node = nullptr ;
410
406
this ->node_count = 0 ;
411
- #if OPENAGE_PAIRINGHEAP_DEBUG
407
+ for (auto &node : nodes) {
408
+ delete node;
409
+ }
412
410
this ->nodes .clear ();
413
- #endif
414
411
}
415
412
416
413
/* *
@@ -583,7 +580,7 @@ class PairingHeap final {
583
580
this ->walk_tree (this ->root_node , func);
584
581
}
585
582
586
- protected :
583
+ private :
587
584
void walk_tree (const element_t &root,
588
585
const std::function<void (const element_t &)> &func) const {
589
586
func (root);
@@ -607,16 +604,17 @@ class PairingHeap final {
607
604
* O(1)
608
605
*/
609
606
void push_node (const element_t &node) {
610
- this ->root_insert (node);
607
+ auto [iter, result] = this ->nodes .insert (node);
608
+ if (result) {
609
+ this ->root_insert (node);
610
+ this ->node_count += 1 ;
611
+ }
611
612
612
613
#if OPENAGE_PAIRINGHEAP_DEBUG
613
- auto ins = this ->nodes .insert (node);
614
- if (not ins.second ) {
614
+ if (not result) {
615
615
throw Error{ERR << " node already known" };
616
616
}
617
617
#endif
618
-
619
- this ->node_count += 1 ;
620
618
}
621
619
622
620
/* *
@@ -631,14 +629,10 @@ class PairingHeap final {
631
629
}
632
630
}
633
631
634
- protected:
635
632
compare cmp;
636
633
size_t node_count;
637
634
element_t root_node;
638
-
639
- #if OPENAGE_PAIRINGHEAP_DEBUG
640
635
std::unordered_set<element_t > nodes;
641
- #endif
642
636
};
643
637
644
638
} // namespace openage::datastructure
0 commit comments