1 module mergearray.seqpq.pairingheap; 2 3 /++ 4 A sequential Pairing Heap implementation of a priority queue of elements T using 5 allocator Alloc. 6 +/ 7 struct PairingHeap(T, Alloc) { 8 private: 9 struct Node { 10 Node* child; 11 Node* next; 12 T value = void; 13 14 this(T t) { 15 value = t; 16 } 17 18 static auto merge(Node* a, Node* b) pure 19 in { 20 assert(a is null || a.next is null); 21 assert(b is null || b.next is null); 22 } 23 body { 24 if (a is null) { 25 return b; 26 } 27 if (b is null) { 28 return a; 29 } 30 31 if (a.value > b.value) { 32 import std.algorithm; 33 swap(a, b); 34 } 35 36 b.next = a.child; 37 a.child = b; 38 39 return a; 40 } 41 } 42 43 static struct NodeRange { 44 Node* front; 45 void popFront() { front = front.next; } 46 @property bool empty() const { return front is null; } 47 @property NodeRange save() { return this; } 48 } 49 50 void mergeReduce() { 51 if (head is null) { 52 return; 53 } 54 55 if (head.child is null) { 56 return; 57 } 58 59 // optimized/inlined to the same code in deleteMin ??? 60 enum UseRecursion = true; 61 62 static if (UseRecursion) { 63 Node* rec(NodeRange r) pure { 64 if (r.empty) { 65 return null; 66 } 67 auto first = r.front; 68 r.popFront(); 69 70 if (r.empty) { 71 return first; 72 } 73 auto second = r.front; 74 r.popFront(); 75 76 first.next = null; 77 second.next = null; 78 79 return Node.merge(Node.merge(first, second), rec(r)); 80 } 81 82 head.child = rec(NodeRange(head.child)); 83 } 84 else { 85 Node* acc = null; 86 NodeRange r = NodeRange(head.child); 87 88 while(true) { 89 if (r.empty) { 90 break; 91 } 92 auto first = r.front; 93 r.popFront(); 94 95 if (r.empty) { 96 acc = Node.merge(acc, first); 97 break; 98 } 99 auto second = r.front; 100 r.popFront(); 101 102 first.next = null; 103 second.next = null; 104 105 acc = Node.merge(acc, Node.merge(first, second)); 106 } 107 108 head.child = acc; 109 } 110 } 111 112 Node* head; 113 size_t size = 0; 114 115 public: 116 /++ 117 The number of bytes allocated per element inserted. 118 +/ 119 enum size_t NodeSize = Node.sizeof; 120 121 /++ 122 Property returning true if and only if the container has no elements. 123 Complexity: O(1) 124 +/ 125 @property 126 bool empty() const { 127 return head is null; 128 } 129 /++ 130 Returns the number of elements in the container. 131 Complexity: O(1) 132 +/ 133 @property 134 size_t length() const { 135 return size; 136 } 137 138 /++ 139 Inserts t into the container. 140 Complexity: O(1) 141 +/ 142 void insert(T t) { 143 size++; 144 145 Node* n = Alloc.alloc!Node(t); 146 147 head = Node.merge(head, n); 148 } 149 150 import std.typecons : Nullable; 151 /++ 152 Removes the element with the minimum value. 153 Complexity: O(log n) 154 +/ 155 Nullable!T deleteMin() { 156 mergeReduce(); 157 158 if (empty) { 159 return Nullable!T(); 160 } 161 else { 162 auto t = Nullable!T(head.value); 163 head = head.child; 164 165 size--; 166 167 return t; 168 } 169 } 170 171 /++ 172 Returns the minimum element of the container. 173 Complexity: O(1) 174 +/ 175 @property 176 Nullable!T peekMin() { 177 if (empty) { 178 return Nullable!T(); 179 } 180 else { 181 return Nullable!T(head.value); 182 } 183 } 184 185 /++ 186 Steals the elements of other and inserts them (in bulk) into this container. 187 188 Other is left empty. 189 190 Complexity: O(1) 191 +/ 192 void mergeSteal(ref PairingHeap other) { 193 head = Node.merge(head, other.head); 194 other.head = null; 195 196 size += other.size; 197 other.size = 0; 198 } 199 }