1 module dkh.container.pairingheap; 2 3 private NP meldPairingHeapNode(alias less, NP)(NP x, NP y) { 4 import std.algorithm : swap; 5 if (!x) return y; 6 if (!y) return x; 7 if (less(x._item, y._item)) swap(x, y); 8 y.next = x.head; 9 x.head = y; 10 return x; 11 } 12 13 /// 14 struct PairingHeap(T, alias less = "a < b") { 15 import std.functional : binaryFun; 16 private alias _less = binaryFun!less; 17 18 private alias NP = Node*; 19 private static struct Node { 20 T _item; 21 NP head, next; 22 this(T item) { 23 _item = item; 24 } 25 } 26 27 private struct Payload { 28 import std.algorithm : swap; 29 private NP node; 30 private uint len; 31 32 void insert(T item) { 33 len++; 34 node = meldPairingHeapNode!_less(node, new Node(item)); 35 } 36 inout(T) front() inout { return node._item; } 37 void removeFront() { 38 len--; 39 40 NP s = node.head; 41 NP t; 42 // merge and reverse: (s, s.next, s.next.next, ...) 43 // result: (..., t.next.next, t.next, t) 44 while (s) { 45 // pop first 2 nodes 46 NP first, second; 47 first = s; s = s.next; first.next = null; 48 if (s) { 49 second = s; s = s.next; second.next = null; 50 } 51 // merge 2 nodes and insert front of t 52 auto v = meldPairingHeapNode!_less(first, second); 53 v.next = t; 54 t = v; 55 } 56 node = null; 57 // merge t 58 while (t) { 59 NP first = t; t = t.next; first.next = null; 60 node = meldPairingHeapNode!_less(first, node); 61 } 62 } 63 void meld(Payload* r) { 64 len += r.len; r.len = 0; 65 node = meldPairingHeapNode!_less(node, r.node); 66 r.node = null; 67 } 68 } 69 private Payload* _p; 70 71 @property bool empty() const { return !_p || _p.len == 0; } /// 72 @property size_t length() const { return (!_p) ? 0 : _p.len; } /// 73 74 void insert(T item) { 75 if (!_p) _p = new Payload(); 76 _p.insert(item); 77 } /// 78 inout(T) front() inout { 79 assert(!empty, "PairingHeap.front: heap is empty"); 80 return _p.front; 81 } /// 82 void removeFront() { 83 assert(!empty, "PairingHeap.removeFront: heap is empty"); 84 _p.removeFront; 85 } /// 86 /** 87 meld two heaps 88 Warning: r become empty 89 */ 90 void meld(PairingHeap r) { _p.meld(r._p); } 91 } 92 93 /// 94 unittest { 95 auto p1 = PairingHeap!int(); 96 auto p2 = PairingHeap!int(); 97 98 p1.insert(1); 99 p1.insert(2); 100 assert(p1.front == 2); 101 102 p2.insert(3); 103 assert(p2.front == 3); 104 105 p1.meld(p2); 106 assert(p1.length == 3 && !p2.length); 107 108 assert(p1.front == 3); p1.removeFront(); 109 assert(p1.front == 2); p1.removeFront(); 110 assert(p1.front == 1); p1.removeFront(); 111 } 112 113 unittest { 114 import std.random, std.container.binaryheap, std.container.array; 115 int f(T)(Random gen) { 116 T t; 117 int sm = 0; 118 foreach (i; 0..1000) { 119 int ty = uniform(0, 3, gen); 120 if (ty == 0) { 121 //push 122 t.insert(uniform(0, 1000, gen)); 123 } else if (ty == 1) { 124 //top 125 if (t.length) sm ^= i * t.front; 126 } else { 127 //pop 128 if (t.length) t.removeFront; 129 } 130 } 131 return sm; 132 } 133 auto u = Random(unpredictableSeed); 134 import dkh.stopwatch; 135 StopWatch sw; sw.start; 136 foreach (i; 0..1000) { 137 auto seed = u.front; u.popFront; 138 assert( 139 f!(PairingHeap!(int, "a<b"))(Random(seed)) == 140 f!(BinaryHeap!(Array!int))(Random(seed)) 141 ); 142 } 143 import std.stdio; 144 writeln("Start PairingHeap 1000: ", sw.peek.toMsecs); 145 } 146 147 unittest { 148 auto cost(int i) { 149 return i; 150 } 151 auto que = PairingHeap!(int, (a, b) => cost(a) < cost(b))(); 152 que.insert(10); 153 que.removeFront(); 154 }