@@ -38,7 +38,7 @@ class PairingHeap;
3838
3939
4040template <typename T, typename compare = std::less<T>>
41- class PairingHeapNode : public std ::enable_shared_from_this<PairingHeapNode<T, compare>> {
41+ class PairingHeapNode {
4242public:
4343 using this_type = PairingHeapNode<T, compare>;
4444
@@ -47,7 +47,6 @@ class PairingHeapNode : public std::enable_shared_from_this<PairingHeapNode<T, c
4747 T data;
4848 compare cmp;
4949
50- public:
5150 PairingHeapNode (const T &data) :
5251 data{data} {}
5352
@@ -56,6 +55,10 @@ class PairingHeapNode : public std::enable_shared_from_this<PairingHeapNode<T, c
5655
5756 ~PairingHeapNode () = default ;
5857
58+ PairingHeapNode (const this_type &other) = delete ;
59+
60+ this_type &operator =(const this_type &other) = delete ;
61+
5962 /* *
6063 * Get contained node data.
6164 */
@@ -66,14 +69,14 @@ class PairingHeapNode : public std::enable_shared_from_this<PairingHeapNode<T, c
6669 /* *
6770 * Let this node become a child of the given one.
6871 */
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 );
7174 }
7275
7376 /* *
7477 * Add the given node as a child to this one.
7578 */
76- void add_child (const std::shared_ptr< this_type> & new_child) {
79+ void add_child (this_type * const new_child) {
7780 // first child is the most recently attached one
7881 // it must not have siblings as they will get lost.
7982
@@ -85,31 +88,31 @@ class PairingHeapNode : public std::enable_shared_from_this<PairingHeapNode<T, c
8588 }
8689
8790 this ->first_child = new_child;
88- new_child->parent = this -> shared_from_this () ;
91+ new_child->parent = this ;
8992 }
9093
9194 /* *
9295 * This method decides which node becomes the new root node
9396 * by comparing `this` with `node`.
9497 * The new root is returned, it has the other node as child.
9598 */
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;
99102
100103 if (this ->cmp (this ->data , node->data )) {
101- new_root = this -> shared_from_this () ;
104+ new_root = this ;
102105 new_child = node;
103106 }
104107 else {
105108 new_root = node;
106- new_child = this -> shared_from_this () ;
109+ new_child = this ;
107110 }
108111
109112 // children of new root become siblings of new new_child
110113 // -> parent of new child = new root
111114
112- // this whll be set by the add_child method
115+ // this will be set by the add_child method
113116 new_child->prev_sibling = nullptr ;
114117 new_child->next_sibling = nullptr ;
115118
@@ -128,15 +131,15 @@ class PairingHeapNode : public std::enable_shared_from_this<PairingHeapNode<T, c
128131 * Recursive call, one stage for each all childs of the root node.
129132 * This results in the computation of the new subtree root.
130133 */
131- std::shared_ptr< this_type> link_backwards () {
134+ this_type * link_backwards () {
132135 if (this ->next_sibling == nullptr ) {
133136 // reached end, return this as current root,
134137 // the previous siblings will be linked to it.
135- return this -> shared_from_this () ;
138+ return this ;
136139 }
137140
138141 // 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 ();
140143
141144 // then link ourself to the new root.
142145 this ->next_sibling = nullptr ;
@@ -153,9 +156,9 @@ class PairingHeapNode : public std::enable_shared_from_this<PairingHeapNode<T, c
153156 */
154157 void loosen () {
155158 // 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
159162 this ->parent ->first_child = this ->next_sibling ;
160163 }
161164 // if we have a previous sibling
@@ -176,10 +179,10 @@ class PairingHeapNode : public std::enable_shared_from_this<PairingHeapNode<T, c
176179 }
177180
178181private:
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
183186};
184187
185188
@@ -191,10 +194,8 @@ template <typename T,
191194 typename heapnode_t = PairingHeapNode<T, compare>>
192195class PairingHeap final {
193196public:
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 >;
198199
199200 /* *
200201 * create a empty heap.
@@ -204,14 +205,16 @@ class PairingHeap final {
204205 root_node (nullptr ) {
205206 }
206207
207- ~PairingHeap () = default ;
208+ ~PairingHeap () {
209+ this ->clear ();
210+ };
208211
209212 /* *
210213 * adds the given item to the heap.
211214 * O(1)
212215 */
213216 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);
215218 this ->push_node (new_node);
216219 return new_node;
217220 }
@@ -221,25 +224,18 @@ class PairingHeap final {
221224 * O(1)
222225 */
223226 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));
225228 this ->push_node (new_node);
226229 return new_node;
227230 }
228231
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-
236232 /* *
237233 * returns the smallest item on the heap and deletes it.
238234 * also known as delete_min.
239235 * _________
240236 * Ω(log log n), O(2^(2*√log log n'))
241237 */
242- element_t pop_node () {
238+ T pop () {
243239 if (this ->root_node == nullptr ) {
244240 throw Error{MSG (err) << " Can't pop an empty heap!" };
245241 }
@@ -316,36 +312,9 @@ class PairingHeap final {
316312 ret->first_child = nullptr ;
317313
318314 // 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;
349318 }
350319
351320 /* *
@@ -391,21 +360,52 @@ class PairingHeap final {
391360 *
392361 * O(1) (but slower than decrease), and O(pop) when node is the root.
393362 */
394- void update (const element_t &node) {
363+ void update (element_t &node) {
395364 if (node != this ->root_node ) [[likely]] {
396- this ->unlink_node (node);
397- this ->push_node (node);
365+ node = this ->push (this ->remove_node (node));
398366 }
399367 else {
400368 // 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;
402400 }
403401 }
404402
405403 /* *
406404 * erase all elements on the heap.
407405 */
408406 void clear () {
407+ auto delete_node = [](element_t node) { delete node; };
408+ this ->iter_all <true >(delete_node);
409409 this ->root_node = nullptr ;
410410 this ->node_count = 0 ;
411411#if OPENAGE_PAIRINGHEAP_DEBUG
@@ -579,39 +579,59 @@ class PairingHeap final {
579579 }
580580#endif
581581
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 >
582589 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);
584591 }
585592
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,
588603 const std::function<void (const element_t &)> &func) const {
589- func (root);
604+ if constexpr (not reverse) {
605+ func (start);
606+ }
590607
591- if (root ) {
592- auto node = root ->first_child ;
608+ if (start ) {
609+ auto node = start ->first_child ;
593610 while (true ) {
594611 if (not node) {
595612 break ;
596613 }
597614
598- this ->walk_tree (node, func);
615+ this ->walk_tree <reverse> (node, func);
599616 node = node->next_sibling ;
600617 }
618+ if constexpr (reverse) {
619+ func (start);
620+ }
601621 }
602622 }
603623
624+
604625 /* *
605626 * adds the given node to the heap.
606627 * use this if the node was not in the heap before.
607628 * O(1)
608629 */
609630 void push_node (const element_t &node) {
610631 this ->root_insert (node);
611-
612632#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 ) {
615635 throw Error{ERR << " node already known" };
616636 }
617637#endif
@@ -631,7 +651,6 @@ class PairingHeap final {
631651 }
632652 }
633653
634- protected:
635654 compare cmp;
636655 size_t node_count;
637656 element_t root_node;
0 commit comments