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 }