Distances on Directed Graphs in R
1/* File triheap.h - Trinomial Heap
2 * ----------------------------------------------------------------------------
3 * Mark Padgham, adapted from code by Shane Saunders
4 */
5
6/* This version is implemented using the node-pair pointer structure; that is,
7 * nodes have a partner pointer, so that nodes can be paired. In this
8 * implementation, the child pointer points to the highest dimension child
9 * node.
10 */
11
12#include "triheap.h"
13#include <cmath>
14#if SHOW_trih
15#include <cstdio>
16#include <Rcpp.h>
17#endif
18
19
20#define TRUE 1
21#define FALSE 0
22
23/*--- TriHeap ---------------------------------------------------------------*/
24
25/* --- Constructor ---
26 * Allocates a trinomial heap capable of holding $n$ items.
27 */
28TriHeap::TriHeap(size_t n)
29{
30#if SHOW_trih
31 Rcpp::Rcout << "init, ";
32 Rcpp::Rcout.flush ();
33#endif
34
35 /* The maximum number of nodes and the maximum number of trees allowed. */
36 maxNodes = n;
37 maxTrees = 1 + static_cast <size_t> (log(static_cast <double> (n)) /
38 log (3.0));
39
40 /* Allocate space for an array of pointers to trees, and nodes in the heap.
41 * Initialise all array entries to zero, that is, NULL pointers.
42 */
43 trees = new TriHeapNode *[maxTrees];
44 for (size_t i = 0; i < maxTrees; i++)
45 trees[i] = std::nullptr_t ();
46
47 active = new TriHeapNode *[maxTrees];
48 for (size_t i = 0; i < maxTrees; i++)
49 active[i] = std::nullptr_t ();
50
51 nodes = new TriHeapNode *[n];
52 for (size_t i = 0; i < n; i++)
53 nodes[i] = std::nullptr_t ();
54
55 /* We begin with no nodes in the heap. */
56 itemCount = 0;
57
58 /* The value of the heap helps to keep track of the maximum dimension while
59 * nodes are inserted or deleted.
60 */
61 treeSum = 0;
62
63 /* For experimental purposes, we keep a count of the number of key
64 * comparisons.
65 */
66 compCount = 0;
67}
68
69/* --- Destructor ---
70*/
71TriHeap::~TriHeap()
72{
73#if SHOW_trih
74 Rcpp::Rcout << "free, ";
75 Rcpp::Rcout.flush ();
76#endif
77
78 for (size_t i = 0; i < maxNodes; i++) {
79 delete nodes[i];
80 }
81
82 delete [] nodes;
83 delete [] trees;
84 delete [] active;
85
86#if SHOW_trih
87 Rcpp::Rcout << "free-exited, ";
88 Rcpp::Rcout.flush ();
89#endif
90}
91
92/* --- insert() ---
93 * Inserts a new item, $item$, with assoicated key, $k$, into the heap.
94 */
95void TriHeap::insert(size_t item, double k)
96{
97 TriHeapNode *newNode;
98
99#if SHOW_trih
100 Rcpp::Rcout << "insert, ";
101 Rcpp::Rcout.flush ();
102#endif
103
104 /* Create an initialise the new node. The parent pointer will be set to
105 * NULL by meld().
106 */
107 newNode = new TriHeapNode;
108 newNode->child = std::nullptr_t ();
109 newNode->extra = FALSE;
110 newNode->left = newNode->right = std::nullptr_t ();
111 newNode->partner = std::nullptr_t ();
112
113 newNode->dim = 0;
114 newNode->item = item;
115 newNode->key = k;
116
117 /* Maintain a pointer to item's new node in the heap. */
118 nodes[item] = newNode;
119
120 /* Meld the new node into the heap. */
121 meld(newNode);
122
123 /* Update the heap's node count. */
124 itemCount++;
125
126#if SHOW_trih
127 Rcpp::Rcout << "insert-exited, ";
128 Rcpp::Rcout.flush ();
129#endif
130}
131
132/* --- deleteMin() ---
133 * Deletes and returns the minimum node from the heap.
134 */
135size_t TriHeap::deleteMin()
136{
137 TriHeapNode *minNode, *child, *next, *partner;
138 TriHeapNode *head, *tail, *breakNode, *firstChild;
139 TriHeapNode *l, *parent, *childZero, *childHigher;
140 TriHeapNode *ptr, *nextPartner, *nextParent, *nextFirstChild;
141 TriHeapNode *nextChildZero, *nextChildHigher;
142 double k, k2;
143 size_t d, nextDim, v, item;
144 size_t wasExtra;
145
146#if SHOW_trih
147 Rcpp::Rcout << "deleteMin, ";
148 Rcpp::Rcout.flush ();
149#endif
150
151 /* First we determine the maximum dimension tree in the heap. */
152 v = treeSum;
153 d = 0;
154 while(v) {
155 v = v >> 1;
156 d++;
157 };
158 d--;
159
160 /* Now locate the root node with the smallest key, scanning from the
161 * maximum dimension root position, down to dimension 0 root position.
162 * At the same time, scan active nodes. Note that the maximum dimension of
163 * a active node is one less than the maximum dimension main trunk since we
164 * never get active nodes on a main trunk
165 */
166 minNode = trees[d];
167 k = minNode->key;
168 while(d > 0) {
169 d--;
170 next = trees[d];
171 if(next) {
172 if((k2 = next->key) < k) {
173 k = k2;
174 minNode = next;
175 }
176 compCount++;
177 }
178 next = active[d];
179 if(next) {
180 if((k2 = next->key) < k) {
181 k = k2;
182 minNode = next;
183 }
184 compCount++;
185 }
186 }
187
188#if SHOW_trih
189 Rcpp::Rcout << "on vertex no " << minNode->item << ", ";
190 Rcpp::Rcout.flush ();
191#endif
192
193 /* The resulting break-up depends on whether or not minNode is a root node
194 * or an active node.
195 */
196
197 /* An active node may have been destroyed. */
198 if(minNode->parent) {
199 active[minNode->dim] = std::nullptr_t ();
200 }
201
202 /* During break-up breakNode points to the node that `appears' to have
203 * been removed. Initially this is minNode.
204 */
205 breakNode = minNode;
206 d = breakNode->dim;
207 partner = breakNode->partner;
208 firstChild = breakNode->extra ? partner : breakNode;
209 parent = firstChild->parent; /* parent pointer of the broken node. */
210
211 /* A nodes child pointer always points to its highest dimension child,
212 * so child->right is the smallest dimension. For melding the linked list
213 * starting at child->right, we terminate the circular link with a NULL
214 * pointer.
215 *
216 * For the linked list, only the right pointer is used, so the value of the
217 * left pointer will be left undefined.
218 */
219 child = minNode->child;
220 if(child) {
221 head = child->right;
222 ptr = tail = child;
223
224 /* Nodes in this break up may go from active to inactive. */
225 do {
226 ptr = ptr->right;
227 if(active[ptr->dim] == ptr)
228 active[ptr->dim] = std::nullptr_t ();
229 } while(ptr != tail);
230
231 if(parent) {
232 tail->right = parent;
233 tail = parent;
234 }
235 }
236 else {
237 head = tail = parent;
238 }
239
240
241 /* Propagate break-up through the tree until the main trunk is reached.
242 * Nodes on the main trunk are treated like first child and second child
243 * with no parent. Active nodes never occur as a second child.
244 */
245 if(parent) {
246 childZero = parent->child->right;
247 childHigher = firstChild->right;
248 while(1) {
249 /* At the start of the loop links are not yet updated to account for
250 * the node that appears to have been removed.
251 * parent - points to the parent of the last broken node.
252 * partner - points to the partner of the last broken node.
253 * firstChild - is the first child on the trunk of the broken node.
254 * The smaller of parent and partner is pointed to by the linked list,
255 * Since the linked list is updated in advance.
256 */
257
258
259 /* Make the partner of breakNode `parent's partner. Remember the
260 * old value of the parents partner pointer for the next dimension.
261 * Also remember the value of parent->dim.
262 */
263 nextDim = parent->dim;
264 parent->dim = d;
265 nextPartner = parent->partner;
266 parent->partner = partner;
267 partner->partner = parent;
268
269 /* For the last node pair added to the linked list
270 * (i.e. (parent,partner) or (partner,parent)), we ensure that the
271 * correct node is labelled as extra.
272 */
273 wasExtra = parent->extra;
274 tail->extra = FALSE;
275 tail->partner->extra = TRUE;
276
277 /* Obtain future values of pointer variables now. This is done because
278 * constructing the linked list overwrites pointers that are followed.
279 */
280 if(wasExtra) {
281 nextFirstChild = nextPartner;
282 }
283 else {
284 nextFirstChild = parent;
285 }
286 nextParent = nextFirstChild->parent;
287 nextChildZero = std::nullptr_t ();
288 nextChildHigher = std::nullptr_t ();
289 if(nextParent) {
290 nextChildZero = nextParent->child->right;
291 nextChildHigher = nextFirstChild->right;
292 }
293
294
295 /* Add the child pairs of `parent' that have a greater dimension than
296 * firstChild to the list of broken trunks. Keep a pointer to
297 * parent->child->right for use below.
298 */
299 if(parent->child != firstChild) {
300 ptr = tail;
301 tail->right = childHigher;
302 tail = parent->child;
303
304 /* Nodes in this break up may go from active to inactive.
305 */
306 do {
307 ptr = ptr->right;
308 if(active[ptr->dim] == ptr)
309 active[ptr->dim] = std::nullptr_t ();
310 } while(ptr != tail);
311 }
312
313
314 /* Update the list of children of `parent' to only include those of
315 * lower dimension than firstChild.
316 */
317 if(d) {
318 /* Lower dimension children exist. Note that tail currently points
319 * to the highest dimension child.
320 */
321 l = firstChild->left;
322 l->right = childZero;
323 childZero->left = l;
324 parent->child = l;
325 }
326 else {
327 /* No lower dimension children. */
328 parent->child = std::nullptr_t ();
329 }
330
331
332 /* Now continue break up at 1 dimension higher up by treating `parent'
333 * as the node that has been broken.
334 * Note that on ending, nextParent will be NULL, and we only require
335 * `partner' and d to be updated before exiting.
336 */
337 partner = nextPartner;
338 d = nextDim;
339 if(!nextParent) break;
340 breakNode = parent;
341 parent = nextParent;
342 firstChild = nextFirstChild;
343
344
345 /* Pointers to the dimension zero child of parent, and the next highest
346 * dimension child from firstChild.
347 */
348 childZero = nextChildZero;
349 childHigher = nextChildHigher;
350
351
352 /* Update the linked list in advance to point to the next breakNode,
353 * usually `parent', but possibly `partner' if `partner' is active.
354 */
355 if(wasExtra) {
356
357 /* Since breakNode is not active, `partner' may be, so we may
358 * need to swap the order of `partner' and `parent' in the trunk
359 * resulting from break-up.
360 */
361 if(active[d] == partner) {
362 active[d] = std::nullptr_t ();
363 if(partner->key < parent->key) {
364 /* We make the linked list point to `partner' instead of
365 * `parent', and make parent an extra node.
366 */
367 tail->right = partner;
368 tail = partner;
369 continue; /* Back to start of loop. */
370 }
371 compCount++;
372 }
373 }
374 else {
375 if(active[d] == breakNode)
376 active[d] = std::nullptr_t ();
377 }
378 tail->right = parent;
379 tail = parent;
380
381 }} /* if-while */
382
383
384 /* Break up always propagates up to the main trunk level. After break up
385 * the length the main trunk decreases by one. The current tree position
386 * will become empty unless breakNode has a partner node.
387 */
388 if(partner) {
389 partner->partner = std::nullptr_t ();
390
391 if(partner->extra) {
392 partner->extra = FALSE;
393 partner->parent = std::nullptr_t ();
394 partner->left = partner->right = partner;
395 trees[d] = partner;
396 }
397 }
398 else {
399 trees[d] = std::nullptr_t ();
400 treeSum -= (1 << d);
401 }
402 itemCount--;
403
404 /* Meld the linked list of trunks resulting from break-up into the main
405 * trunk level of the heap.
406 */
407 if(head) {
408 tail->right = std::nullptr_t ();
409 meld(head);
410 }
411
412 /* Record the vertex no to return. */
413 item = minNode->item;
414
415 /* Delete the old minimum node. */
416 nodes[item] = std::nullptr_t ();
417 delete minNode;
418
419#if SHOW_trih
420 Rcpp::Rcout << "deleteMin-exited, ";
421 Rcpp::Rcout.flush ();
422#endif
423
424 return item;
425}
426
427/* --- decreaseKey() ---
428 * This mthod decreases the key of the node corresponding to $item$ to
429 * $newValue$. It is up to the user to ensure that $newValue$ is in-fact less
430 * than or equal to the current value.
431 */
432void TriHeap::decreaseKey(size_t item, double newValue)
433{
434 TriHeapNode *v, *v2, *w, *w2, *p, *above, *partner, *activeNode;
435 TriHeapNode *l, *r, *lowChild, *highChild, *ptr;
436 size_t d;
437
438#if SHOW_trih
439 Rcpp::Rcout << "decreaseKey on vn = " << item << "(" << newValue << "), ";
440 Rcpp::Rcout.flush ();
441#endif
442
443
444 /* Pointer v points to the decreased node. */
445 v = nodes[item];
446 v->key = newValue;
447 d = v->dim; /* dimension */
448
449
450 /* This loop allows rearrangement to propagate to higher dimensions. */
451 while(1) {
452
453
454 v2 = v->partner; /* partner */
455 if(v->extra) {
456 p = v2->parent; /* parent */
457 above = v2;
458 }
459 else {
460 above = p = v->parent; /* parent */
461 }
462
463
464 /* Determine if rearrangement is necessary */
465
466 /* If v is a root node, then rearrangement is not necessary. */
467 if(!above) return;
468
469 if(p) {
470 /* Non-main trunk. */
471
472 activeNode = active[d];
473
474 if(v->extra) {
475 /* v is a second child. If necessary, we swap with the first
476 * child to maintain the correct ordering.
477 */
478
479 compCount++;
480 if(v->key < above->key) {
481 /* swap */
482 v->extra = FALSE;
483 v2->extra = TRUE;
484 replaceChild(v2, v);
485
486 /* If v2 is inconsistent try promotion. By checking if
487 * v2 was an active node we can avoid key comparison, since
488 * v2 can only be inconsistent if it is active.
489 */
490 if(activeNode == v2) {
491
492 compCount++;
493 if(v2->key < p->key) goto promote; /* see below */
494
495 /* At this point, v2 is active but is consistent, so v
496 * will replace it as the active node, regardless of
497 * whether v is inconsistent or not.
498 */
499 active[d] = v;
500 return;
501 }
502
503 /* If there is some other active node for this dimension.
504 * try rearrangement with it.
505 */
506 if(activeNode) goto rearrange; /* see below */
507
508 /* Otherwise we can make v an active node, regardless of
509 * whether v is inconsistent or not.
510 */
511 active[d] = v;
512 return;
513 }
514
515 /* Otherwise don't swap */
516
517 /* We may need to promote, but only if both v and v2 are
518 * inconsistent. By checking if v2 is already active, we
519 * can avoid key comparison since v2 won't be inconsistent
520 * if it is not active.
521 */
522 if(activeNode == v2) {
523 /* If v is inconsistent, then v2 is also, so promote. */
524 compCount++;
525 if(v->key < p->key) {
526 /* Swap v and v2. */
527 v2 = v;
528 v = above;
529 goto promote;
530 }
531
532 /* Otherwise promotion is not necessary. */
533 return;
534 }
535
536 /* At this point, promotion is not necessary. */
537 return;
538 }
539
540 /* Otherwise, v is a first child. */
541
542 if(activeNode) {
543 /* If v is already the active node leave it. */
544 if(activeNode == v) return;
545
546 /* Otherwise some other node is active, so try
547 * rearrangement.
548 */
549 goto rearrange; /* see below */
550 }
551
552 /* At this point, there is no active node, so make v the active
553 * node, as it is possibly inconsistent.
554 */
555 active[d] = v;
556 return;
557 }
558
559 /* Otherwise, v is the second node on a main trunk. */
560
561 compCount++;
562 if(v->key < above->key) {
563 /* If v is smaller, we swap it with the first child
564 * (i.e. the root node) to maintain the correct ordering.
565 */
566 v->extra = FALSE;
567 v2->extra = TRUE;
568 v->parent = std::nullptr_t ();
569 v->left = v->right = v;
570 trees[d] = v;
571 return;
572 }
573
574 /* Otherwise, no rearrangement is required since heap order is still
575 * satisfied.
576 */
577 return;
578
579 /*------------------------------*/
580rearrange:
581
582 /* At this stage v is a first child and possibly inconsistent, but not
583 * an active node. Node v2 is consistent. Rearrangement occurs with
584 * the currently active node for this dimension, which at this point
585 * must exist.
586 */
587
588
589 /* The current active node and its partner are w and w2 respectively.
590 */
591 w = activeNode;
592 w2 = w->partner;
593
594 /* The final rearrangement always pairs v with w and v2 with w2. */
595 v->partner = w; w->partner = v;
596 v2->partner = w2; w2->partner = v2;
597
598 /* Determine the ordering in the rearrangement. */
599 compCount++;
600 if(v2->key < w2->key) {
601 /* Make the (1st child, 2nd child) pair (v2,w2), replacing (v,v2).
602 */
603 v2->extra = FALSE;
604 replaceChild(v, v2);
605
606 compCount++;
607 if(v->key < w->key) {
608 /* Make the pair (v,w), replacing (w,w2). */
609 w->extra = TRUE;
610 replaceChild(w,v);
611
612 compCount++;
613 if(w->key < v->parent->key) {
614 /* Both v and w are inconsistent, continue with
615 * promotion. Update v2, and p;
616 */
617 v2 = w;
618 p = v->parent;
619 goto promote; /* see below */
620 }
621
622 /* Otherwise, although w is active, it is not inconsistent.
623 * In this case we do not do promotion. Instead, v replaces w
624 * as the active node, although v may not be inconsistent.
625 * (Avoids a key comparison to check if v is consistent)
626 */
627 active[d] = v;
628 return;
629 }
630 else {
631 /* Make the pair (w,v), replacing (w,w2). */
632 v->extra = TRUE;
633
634 compCount++;
635 if(v->key < w->parent->key) {
636 /* Both v and w are inconsistent, so continue with
637 * promotion. Update v, v2, and p.
638 */
639 v2 = v;
640 v = w;
641 p = w->parent;
642 goto promote; /* see below */
643 }
644
645 /* Only w is possibly inconsistent, so it remains the active
646 * node.
647 */
648 return;
649 }
650 }
651 else {
652 /* Make the pair (w2,v2), replacing (w,w2). */
653 w2->extra = FALSE;
654 replaceChild(w, w2);
655
656 compCount++;
657 if(v->key < w->key) {
658 /* Make the pair (v,w), replacing (v,v2). */
659 w->extra = TRUE;
660
661 compCount++;
662 if(w->key < v->parent->key) {
663 /* Both v and w are inconsistent, so continue with
664 * promotion. Update v2.
665 */
666 v2 = w;
667 goto promote; /* see below */
668 }
669
670 /* Only v is possibly inconsistent, so it becomes the active
671 * node.
672 */
673 active[d] = v;
674 return;
675 }
676 else {
677 /* Make the pair (w,v), replacing (v,v2). */
678 v->extra = TRUE;
679 replaceChild(v,w);
680
681 compCount++;
682 if(v->key < w->parent->key) {
683 /* Both v and w are inconsistent, so continue with
684 * promotion. Update v, v2.
685 */
686 v2 = v;
687 v = w;
688 goto promote;
689 }
690
691 /* Only w is possibly inconsistent, so it remains the
692 * active node.
693 */
694 return;
695 }
696 }
697
698 /*------------------------------*/
699promote:
700 /* Promotion Code. Reached if the loop has not exited. Uses variables
701 * p, v, v2, and d. Must ensure that on the trunk (p,v,v2), both v and
702 * v2 are inconsistent nodes, so that (v,v2,p) will give heap
703 * ordering.
704 */
705
706 /* First we make v2 a child node of v. */
707 v2->extra = FALSE;
708 addChild(v, v2);
709
710 /* Then v replaces p. Any child nodes of p that have a higher
711 * dimension than v will become child nodes of v. Only child nodes of
712 * lower dimension than v will be left under p.
713 */
714
715 v->dim = p->dim;
716 partner = v->partner = p->partner;
717 highChild = p->child;
718
719 if(d) {
720 /* v has lower dimension siblings. */
721 l = p->child = v->left;
722 r = highChild->right;
723 l->right = r;
724 r->left = l;
725 }
726 else {
727 /* v was an only child. */
728 p->child = std::nullptr_t ();
729 }
730
731 if(highChild != v) {
732 /* v has higher dimension siblings. Add them to the list of v's
733 * children, and update their parent pointer. Note that v
734 * currently has at least one child, since v2 was made a child
735 * of v.
736 */
737 lowChild = v->right;
738 l = v->child;
739 r = v->child->right;
740 l->right = lowChild;
741 lowChild->left = l;
742 r->left = highChild;
743 highChild->right = r;
744
745 v->child = highChild;
746
747 ptr = v;
748 do {
749 ptr = ptr->right;
750 ptr->parent = v;
751 } while(ptr != highChild);
752 }
753
754 /* partner may be NULL if p is a root node, so don't update
755 * partner->partner yet. See update below.
756 */
757
758 /* If p was an extra node no further pointer updates are required. */
759
760 /* Further pointer updates are only needed if p is a first child or a
761 * root node.
762 */
763 if(!p->extra) {
764 if(p->parent) {
765 /* p is non-root node and a first child. */
766 partner->partner = v;
767 replaceChild(p, v);
768 }
769 else {
770 /* p is a root node, so update the tree pointer. */
771 if(partner) partner->partner = v;
772 trees[p->dim] = v;
773 v->left = v->right = v;
774 v->parent = std::nullptr_t ();
775 }
776
777 /* p will become an extra node, see below. */
778 p->extra = TRUE;
779 }
780 else {
781 /* If p was an extra node then v becomes an extra node. */
782 partner->partner = v;
783 v->extra = TRUE;
784 }
785
786 /* Finally, make p the partner of node v2 (i.e. the 2nd child of
787 * node v).
788 */
789 p->dim = d;
790 v2->partner = p;
791 p->partner = v2;
792
793 /* The result of promotion is to release the active node. */
794 active[d] = std::nullptr_t ();
795
796 d = v->dim; /* next dimension, moving up */
797
798 /* If p was an active node, it no longer is, and v takes its place
799 * as an active node.
800 */
801 if(active[d] == p) {
802 active[d] = v;
803 return;
804 }
805
806 /* Rearrangement continues at a higher dimension, since the position of
807 * v has moved up, meaning v may be an inconsistent node.
808 */
809 }
810
811#if SHOW_trih
812 Rcpp::Rcout << "decrease_key-exited, ";
813 Rcpp::Rcout.flush ();
814#endif
815
816}
817
818/*--- TriHeap (private methods) ---------------------------------------------*/
819
820/* --- meld() ---
821 * Melds the linked list of trees pointed to by *treeList into the heap.
822 * This function uses the `right' sibling pointer of nodes to traverse the
823 * linked list from lower dimension nodes to higher dimension nodes.
824 * It expects the last nodes `right' pointer to be NULL.
825 */
826void TriHeap::meld(TriHeapNode *treeList)
827{
828 TriHeapNode *next, *addTree;
829 TriHeapNode *carryTree;
830 size_t d;
831
832#if SHOW_trih
833 Rcpp::Rcout << "meld - ";
834 Rcpp::Rcout.flush ();
835#endif
836
837 /* addTree points to the tree to be merged. */
838 addTree = treeList;
839
840 carryTree = std::nullptr_t ();
841
842 do {
843 /* addTree() gets merged into the heap, and also carryTree if one
844 * exists from a previous merge.
845 */
846
847 /* Keep a pointer to the next tree and remove sibling and parent links
848 * from the current tree. The dimension of the next tree is always
849 * one greater than the dimension of the previous tree, so this merging
850 * is like an addition of two ternary numbers.
851 *
852 * Note that if addTree is NULL and the loop has not exited, then
853 * there is only a carryTree to be merged, so treat it like addTree.
854 */
855 next = std::nullptr_t ();
856 if(addTree) {
857 next = addTree->right;
858 addTree->right = addTree->left = addTree;
859 addTree->parent = std::nullptr_t ();
860 }
861 else {
862 addTree = carryTree;
863 carryTree = std::nullptr_t ();
864 }
865
866#if SHOW_trih
867 Rcpp::Rcout << addTree->item << ", ";
868 Rcpp::Rcout.flush ();
869#endif
870
871 /* First we merge addTree with carryTree, if there is one. Note that
872 * carryTree contains only one node in its main trunk, and addTree
873 * has at most two, so the result is at most one 3-node trunk, which is
874 * treated as a 1-node main trunk one dimension higher up.
875 */
876 if(carryTree) {
877 compCount += merge(&addTree, &carryTree);
878 }
879
880 /* After the merge, if addTree is NULL, then the resulting tree
881 * pointed to by carryTree carries to higher entry, so we do not need
882 * to merge anything into the existing main trunk.
883 * If addTree is not NULL we add it to the existing main trunk.
884 */
885 if(addTree) {
886 d = addTree->dim;
887 if(trees[d]) {
888 /* Nodes already in this main trunk position, so merge. */
889 compCount += merge(&trees[d], &addTree);
890 if(!trees[d]) treeSum -= (1 << d);
891 carryTree = addTree;
892 }
893 else {
894 /* No nodes in this main trunk position, so use addTree. */
895 trees[d] = addTree;
896 treeSum += (1 << d);
897 }
898 }
899
900 /* Obtain a pointer to the next tree to add. */
901 addTree = next;
902
903 /* We continue if there is still a node in the list to be merged, or
904 * a carry tree remains to be merged.
905 */
906 } while(addTree || carryTree);
907
908
909#if SHOW_trih
910 Rcpp::Rcout << "meld-exited, ";
911 Rcpp::Rcout.flush ();
912#endif
913
914}
915
916/*--- TriHeap (node manipulation methods) -----------------------------------*/
917
918/* --- merge() ---
919 * Merges the two trunks pointed to by *a and *b, returning the
920 * sum trunk through `a' and any carry tree through `b'.
921 * When this function is used, both parameters `a' and `b' refer to either
922 * a 1-node or 2-node trunk.
923 *
924 * Returns the number of key comparisons used.
925 */
926size_t TriHeap::merge(TriHeapNode **a, TriHeapNode **b)
927{
928 TriHeapNode *tree, *nextTree, *other, *nextOther;
929 size_t c;
930
931 /* Number of comparisons. */
932 c = 0;
933
934 /* `tree' always points to the node with the lowest key.
935 * To begin with, `tree' points to the smaller head node, and `other'
936 * points to the head node of the other trunk.
937 */
938 if((*a)->key <= (*b)->key) {
939 tree = (*a);
940 other = (*b);
941 }
942 else {
943 tree = (*b);
944 other = (*a);
945 }
946 c++;
947
948 /* nextTree points to the next node on the trunk that `tree' is the head
949 * of (if there is another node).
950 * nextOther points to the next node on the trunk that `other' is the head
951 * of (if there is another node).
952 */
953 nextTree = tree->partner;
954 nextOther = other->partner;
955
956 /* The merging depends on the existence of nodes and the values of keys. */
957 if(!nextTree) {
958 /* nextTree does not exist, so we simply make `other' the child of
959 * `tree'. If nextOther exist the resulting 3-node trunk is a carry
960 * tree.
961 */
962
963 if(nextOther) {
964 addChild(tree, other);
965 tree->dim++;
966 *a = std::nullptr_t ();
967 *b = tree;
968 }
969 else {
970 tree->partner = other;
971 other->partner = tree;
972 other->extra = TRUE;
973
974 *a = tree;
975 *b = std::nullptr_t ();
976 }
977 }
978 else if(!nextOther) {
979 /* nextTree exists but nextOther does not, so the linked order of
980 * nextTree and `other' in the resulting 3-node trunk depends on the
981 * values of keys. The resulting 3-node trunk becomes a carry tree.
982 */
983
984 tree->partner = std::nullptr_t ();
985 other->partner = nextTree;
986 nextTree->partner = other;
987
988 if(other->key < nextTree->key) {
989 addChild(tree, other);
990 }
991 else {
992 nextTree->extra = FALSE;
993 other->extra = TRUE;
994 addChild(tree, nextTree);
995 }
996
997 tree->dim++;
998
999 c++;
1000 *a = std::nullptr_t ();
1001 *b = tree;
1002 }
1003 else {
1004 /* Otherwise, both nextTree and nextOther exist. The result consists
1005 * of a 1 node trunk plus the 3-node trunk which becomes a carry tree.
1006 * We two trunks are made up as (tree, other, nextOther)
1007 * and (nextTree). This uses no key comparisons.
1008 */
1009
1010 tree->partner = std::nullptr_t ();
1011 nextTree->partner = std::nullptr_t ();
1012 nextTree->extra = FALSE;
1013 nextTree->left = nextTree->right = nextTree;
1014 nextTree->parent = std::nullptr_t ();
1015
1016 addChild(tree, other);
1017
1018 tree->dim++;
1019
1020 *a = nextTree; *b = tree;
1021 }
1022
1023 return c;
1024}
1025
1026/* --- addChild() ---
1027 * Adds the child node pointeed to by $c$ to the parent node pointed to by $p$.
1028 * The user should ensure that the correct dimension child is being added.
1029 */
1030void TriHeap::addChild(TriHeapNode *p, TriHeapNode *c)
1031{
1032 TriHeapNode *l, *r;
1033
1034 /* If $p$ already has child nodes we must update the sibling pointers.
1035 * Otherwise only initialise the left and right pointers of the added
1036 * child.
1037 */
1038 if((l = p->child)) {
1039 r = l->right;
1040 c->left = l;
1041 c->right = r;
1042 r->left = c;
1043 l->right = c;
1044 }
1045 else {
1046 c->left = c->right = c;
1047 }
1048
1049 p->child = c;
1050 c->parent = p;
1051}
1052
1053
1054/* --- replaceChild() ---
1055 * Replaces child node pointed to by $oldNode$ and its associated sub-tree with the
1056 * child node pointed to by $newNode$ and its associated sub-tree.
1057 */
1058void TriHeap::replaceChild(TriHeapNode *oldNode, TriHeapNode *newNode)
1059{
1060 TriHeapNode *parent, *l, *r;
1061
1062 r = oldNode->right;
1063
1064 /* If $oldNode$ is an only child we only need to initialise the sibling
1065 * pointers of the new node. Otherwise we update sibling pointers of other
1066 * child nodes.
1067 */
1068 if(r == oldNode) {
1069 newNode->right = newNode->left = newNode;
1070 }
1071 else {
1072 l = oldNode->left;
1073 l->right = newNode;
1074 r->left = newNode;
1075 newNode->left = l;
1076 newNode->right = r;
1077 }
1078
1079 /* Update parent pointer of the new node and possibly the child pointer
1080 * of the parent node.
1081 */
1082 parent = oldNode->parent;
1083 newNode->parent = parent;
1084 if(parent->child == oldNode) parent->child = newNode;
1085}
1086
1087/*--- TriHeap (debugging) ---------------------------------------------------*/
1088
1089/* --- dumpNodes() ---
1090 * Recursively print the nodes of a trinomial heap.
1091 */
1092//TriHeapNode **Active;
1093void TriHeap::dumpNodes(TriHeapNode *node, size_t level)
1094{
1095#if SHOW_trih
1096 TriHeapNode *childNode, *partnerNode;
1097 size_t childCount;
1098
1099 /* Print leading whitespace for this level. */
1100 for (size_t i = 0; i < level; i++)
1101 Rcpp::Rcout << " ";
1102
1103 Rcpp::Rcout << node->item << "(" << node->key << ")" << std::endl;
1104
1105 if((childNode = node->child)) {
1106 childNode = node->child->right;
1107
1108 childCount = 0;
1109
1110 do {
1111 dumpNodes(childNode, level+1);
1112 if(childNode->dim != childCount) {
1113 for (size_t i = 0; i < level+1; i++)
1114 Rcpp::Rcout << " ";
1115 throw std::runtime_error ("error(dim)");
1116 }
1117 if(childNode->parent != node) {
1118 for (size_t i = 0; i < level+1; i++)
1119 Rcpp::Rcout << " ";
1120 throw std::runtime_error ("error(parent)");
1121 }
1122 if(Active[childNode->dim] != childNode &&
1123 childNode->key < node->key) {
1124 for (size_t i = 0; i < level; i++)
1125 Rcpp::Rcout << " ";
1126 throw std::runtime_error ("error(key)");
1127 }
1128 childNode = childNode->right;
1129 childCount++;
1130 } while(childNode != node->child->right);
1131
1132 if(childCount != node->dim) {
1133 for (size_t i = 0; i < level; i++)
1134 Rcpp::Rcout << " ";
1135 throw std::runtime_error ("error(childCount)");
1136 }
1137 }
1138 else {
1139 if(node->dim != 0) {
1140 for (size_t i = 0; i < level; i++)
1141 Rcpp::Rcout << " ";
1142 throw std::runtime_error ("error(dim)");
1143 }
1144 }
1145
1146 if((partner=node->partner)) {
1147 if(node->extra==partner->extra) {
1148 for (size_t i = 0; i < level; i++)
1149 Rcpp::Rcout << " ";
1150 Rcpp::Rcout << partner->item;
1151 throw std::runtime_error (" - error(extra?)");
1152 }
1153 if(partner->extra) {
1154 if(partner->dim != node->dim) {
1155 for (size_t i = 0; i < level; i++)
1156 Rcpp::Rcout << " ";
1157 Rcpp::Rcout << partner->item;
1158 throw std::runtime_error (" - error(dim)");
1159 }
1160
1161 dumpNodes(partner, level);
1162 if(partner->key < node->key) {
1163 for (size_t i = 0; i < level; i++)
1164 Rcpp::Rcout << " ";
1165 throw std::runtime_error ("error(key)");
1166 }
1167 }
1168 }
1169 else if(node->parent) {
1170 for (size_t i = 0; i < level; i++)
1171 Rcpp::Rcout << " ";
1172 throw std::runtime_error ("error(no partner)");
1173 }
1174#endif
1175}
1176
1177/* --- dump() ---
1178 * Print out a trinomial heap.
1179 */
1180void TriHeap::dump() const
1181{
1182#if SHOW_trih
1183 TriHeapNode *node;
1184
1185 Active = active;
1186
1187 Rcpp::Rcout << std::endl << "value = " << treeSum << std::endl;
1188 Rcpp::Rcout << "array entries 0..maxTrees =";
1189 for (size_t i=0; i<maxTrees; i++) {
1190 bool tempval = trees [i] ? 1 : 0
1191 Rcpp::Rcout << " " << tempval;
1192 }
1193 Rcpp::Rcout << std::endl << "active nodes =";
1194 for (size_t i=0; i<maxTrees-1; i++) {
1195 if(active[i]) {
1196 Rcpp::Rcout << " " << active [i]->item;
1197 if(active[i]->dim != i) {
1198 throw std::runtime_error ("-error(dim)");
1199 }
1200 if(active[i]->extra) {
1201 throw std::runtime_error ("-error(extra)");
1202 }
1203 if(!active[i]->parent) {
1204 throw std::runtime_error ("-error(parent)");
1205 }
1206 }
1207 else {
1208 Rcpp::Rcout << " _";
1209 }
1210 }
1211 Rcpp::Rcout << std::endl << std::endl;
1212 for (size_t i=0; i<maxTrees; i++) {
1213 if((node = trees[i])) {
1214 Rcpp::Rcout << "tree " << i << std::endl << std::endl;
1215 dumpNodes(node, 0);
1216 Rcpp::Rcout << std::endl;
1217 }
1218 }
1219 Rcpp::Rcout.flush ();
1220#endif
1221}
1222/*---------------------------------------------------------------------------*/