master
  1const std = @import("std.zig");
  2const assert = std.debug.assert;
  3const testing = std.testing;
  4const Order = std.math.Order;
  5
  6pub fn Treap(comptime Key: type, comptime compareFn: anytype) type {
  7    return struct {
  8        const Self = @This();
  9
 10        // Allow for compareFn to be fn (anytype, anytype) anytype
 11        // which allows the convenient use of std.math.order.
 12        fn compare(a: Key, b: Key) Order {
 13            return compareFn(a, b);
 14        }
 15
 16        root: ?*Node = null,
 17        prng: Prng = .{},
 18
 19        /// A customized pseudo random number generator for the treap.
 20        /// This just helps reducing the memory size of the treap itself
 21        /// as std.Random.DefaultPrng requires larger state (while producing better entropy for randomness to be fair).
 22        const Prng = struct {
 23            xorshift: usize = 0,
 24
 25            fn random(self: *Prng, seed: usize) usize {
 26                // Lazily seed the prng state
 27                if (self.xorshift == 0) {
 28                    self.xorshift = seed;
 29                }
 30
 31                // Since we're using usize, decide the shifts by the integer's bit width.
 32                const shifts = switch (@bitSizeOf(usize)) {
 33                    64 => .{ 13, 7, 17 },
 34                    32 => .{ 13, 17, 5 },
 35                    16 => .{ 7, 9, 8 },
 36                    else => @compileError("platform not supported"),
 37                };
 38
 39                self.xorshift ^= self.xorshift >> shifts[0];
 40                self.xorshift ^= self.xorshift << shifts[1];
 41                self.xorshift ^= self.xorshift >> shifts[2];
 42
 43                assert(self.xorshift != 0);
 44                return self.xorshift;
 45            }
 46        };
 47
 48        /// A Node represents an item or point in the treap with a uniquely associated key.
 49        pub const Node = struct {
 50            key: Key,
 51            priority: usize,
 52            parent: ?*Node,
 53            children: [2]?*Node,
 54
 55            pub fn next(node: *Node) ?*Node {
 56                return nextOnDirection(node, 1);
 57            }
 58            pub fn prev(node: *Node) ?*Node {
 59                return nextOnDirection(node, 0);
 60            }
 61        };
 62
 63        fn extremeInSubtreeOnDirection(node: *Node, direction: u1) *Node {
 64            var cur = node;
 65            while (cur.children[direction]) |next| cur = next;
 66            return cur;
 67        }
 68
 69        fn nextOnDirection(node: *Node, direction: u1) ?*Node {
 70            if (node.children[direction]) |child| {
 71                return extremeInSubtreeOnDirection(child, direction ^ 1);
 72            }
 73            var cur = node;
 74            // Traversing upward until we find `parent` to `cur` is NOT on
 75            // `direction`, or equivalently, `cur` to `parent` IS on
 76            // `direction` thus `parent` is the next.
 77            while (true) {
 78                if (cur.parent) |parent| {
 79                    // If `parent -> node` is NOT on `direction`, then
 80                    // `node -> parent` IS on `direction`
 81                    if (parent.children[direction] != cur) return parent;
 82                    cur = parent;
 83                } else {
 84                    return null;
 85                }
 86            }
 87        }
 88
 89        /// Returns the smallest Node by key in the treap if there is one.
 90        /// Use `getEntryForExisting()` to replace/remove this Node from the treap.
 91        pub fn getMin(self: Self) ?*Node {
 92            if (self.root) |root| return extremeInSubtreeOnDirection(root, 0);
 93            return null;
 94        }
 95
 96        /// Returns the largest Node by key in the treap if there is one.
 97        /// Use `getEntryForExisting()` to replace/remove this Node from the treap.
 98        pub fn getMax(self: Self) ?*Node {
 99            if (self.root) |root| return extremeInSubtreeOnDirection(root, 1);
100            return null;
101        }
102
103        /// Lookup the Entry for the given key in the treap.
104        /// The Entry act's as a slot in the treap to insert/replace/remove the node associated with the key.
105        pub fn getEntryFor(self: *Self, key: Key) Entry {
106            var parent: ?*Node = undefined;
107            const node = self.find(key, &parent);
108
109            return Entry{
110                .key = key,
111                .treap = self,
112                .node = node,
113                .context = .{ .inserted_under = parent },
114            };
115        }
116
117        /// Get an entry for a Node that currently exists in the treap.
118        /// It is undefined behavior if the Node is not currently inserted in the treap.
119        /// The Entry act's as a slot in the treap to insert/replace/remove the node associated with the key.
120        pub fn getEntryForExisting(self: *Self, node: *Node) Entry {
121            assert(node.priority != 0);
122
123            return Entry{
124                .key = node.key,
125                .treap = self,
126                .node = node,
127                .context = .{ .inserted_under = node.parent },
128            };
129        }
130
131        /// An Entry represents a slot in the treap associated with a given key.
132        pub const Entry = struct {
133            /// The associated key for this entry.
134            key: Key,
135            /// A reference to the treap this entry is apart of.
136            treap: *Self,
137            /// The current node at this entry.
138            node: ?*Node,
139            /// The current state of the entry.
140            context: union(enum) {
141                /// A find() was called for this entry and the position in the treap is known.
142                inserted_under: ?*Node,
143                /// The entry's node was removed from the treap and a lookup must occur again for modification.
144                removed,
145            },
146
147            /// Update's the Node at this Entry in the treap with the new node (null for deleting). `new_node`
148            /// can have `undefind` content because the value will be initialized internally.
149            pub fn set(self: *Entry, new_node: ?*Node) void {
150                // Update the entry's node reference after updating the treap below.
151                defer self.node = new_node;
152
153                if (self.node) |old| {
154                    if (new_node) |new| {
155                        self.treap.replace(old, new);
156                        return;
157                    }
158
159                    self.treap.remove(old);
160                    self.context = .removed;
161                    return;
162                }
163
164                if (new_node) |new| {
165                    // A previous treap.remove() could have rebalanced the nodes
166                    // so when inserting after a removal, we have to re-lookup the parent again.
167                    // This lookup shouldn't find a node because we're yet to insert it..
168                    var parent: ?*Node = undefined;
169                    switch (self.context) {
170                        .inserted_under => |p| parent = p,
171                        .removed => assert(self.treap.find(self.key, &parent) == null),
172                    }
173
174                    self.treap.insert(self.key, parent, new);
175                    self.context = .{ .inserted_under = parent };
176                }
177            }
178        };
179
180        fn find(self: Self, key: Key, parent_ref: *?*Node) ?*Node {
181            var node = self.root;
182            parent_ref.* = null;
183
184            // basic binary search while tracking the parent.
185            while (node) |current| {
186                const order = compare(key, current.key);
187                if (order == .eq) break;
188
189                parent_ref.* = current;
190                node = current.children[@intFromBool(order == .gt)];
191            }
192
193            return node;
194        }
195
196        fn insert(self: *Self, key: Key, parent: ?*Node, node: *Node) void {
197            // generate a random priority & prepare the node to be inserted into the tree
198            node.key = key;
199            node.priority = self.prng.random(@intFromPtr(node));
200            node.parent = parent;
201            node.children = [_]?*Node{ null, null };
202
203            // point the parent at the new node
204            const link = if (parent) |p| &p.children[@intFromBool(compare(key, p.key) == .gt)] else &self.root;
205            assert(link.* == null);
206            link.* = node;
207
208            // rotate the node up into the tree to balance it according to its priority
209            while (node.parent) |p| {
210                if (p.priority <= node.priority) break;
211
212                const is_right = p.children[1] == node;
213                assert(p.children[@intFromBool(is_right)] == node);
214
215                const rotate_right = !is_right;
216                self.rotate(p, rotate_right);
217            }
218        }
219
220        fn replace(self: *Self, old: *Node, new: *Node) void {
221            // copy over the values from the old node
222            new.key = old.key;
223            new.priority = old.priority;
224            new.parent = old.parent;
225            new.children = old.children;
226
227            // point the parent at the new node
228            const link = if (old.parent) |p| &p.children[@intFromBool(p.children[1] == old)] else &self.root;
229            assert(link.* == old);
230            link.* = new;
231
232            // point the children's parent at the new node
233            for (old.children) |child_node| {
234                const child = child_node orelse continue;
235                assert(child.parent == old);
236                child.parent = new;
237            }
238        }
239
240        fn remove(self: *Self, node: *Node) void {
241            // rotate the node down to be a leaf of the tree for removal, respecting priorities.
242            while (node.children[0] orelse node.children[1]) |_| {
243                self.rotate(node, rotate_right: {
244                    const right = node.children[1] orelse break :rotate_right true;
245                    const left = node.children[0] orelse break :rotate_right false;
246                    break :rotate_right (left.priority < right.priority);
247                });
248            }
249
250            // node is a now a leaf; remove by nulling out the parent's reference to it.
251            const link = if (node.parent) |p| &p.children[@intFromBool(p.children[1] == node)] else &self.root;
252            assert(link.* == node);
253            link.* = null;
254
255            // clean up after ourselves
256            node.priority = 0;
257            node.parent = null;
258            node.children = [_]?*Node{ null, null };
259        }
260
261        fn rotate(self: *Self, node: *Node, right: bool) void {
262            // if right, converts the following:
263            //      parent -> (node (target YY adjacent) XX)
264            //      parent -> (target YY (node adjacent XX))
265            //
266            // if left (!right), converts the following:
267            //      parent -> (node (target YY adjacent) XX)
268            //      parent -> (target YY (node adjacent XX))
269            const parent = node.parent;
270            const target = node.children[@intFromBool(!right)] orelse unreachable;
271            const adjacent = target.children[@intFromBool(right)];
272
273            // rotate the children
274            target.children[@intFromBool(right)] = node;
275            node.children[@intFromBool(!right)] = adjacent;
276
277            // rotate the parents
278            node.parent = target;
279            target.parent = parent;
280            if (adjacent) |adj| adj.parent = node;
281
282            // fix the parent link
283            const link = if (parent) |p| &p.children[@intFromBool(p.children[1] == node)] else &self.root;
284            assert(link.* == node);
285            link.* = target;
286        }
287
288        /// Usage example:
289        ///   var iter = treap.inorderIterator();
290        ///   while (iter.next()) |node| {
291        ///     ...
292        ///   }
293        pub const InorderIterator = struct {
294            current: ?*Node,
295
296            pub fn next(it: *InorderIterator) ?*Node {
297                const current = it.current;
298                it.current = if (current) |cur|
299                    cur.next()
300                else
301                    null;
302                return current;
303            }
304        };
305
306        pub fn inorderIterator(self: *Self) InorderIterator {
307            return .{ .current = self.getMin() };
308        }
309    };
310}
311
312// For iterating a slice in a random order
313// https://lemire.me/blog/2017/09/18/visiting-all-values-in-an-array-exactly-once-in-random-order/
314fn SliceIterRandomOrder(comptime T: type) type {
315    return struct {
316        rng: std.Random,
317        slice: []T,
318        index: usize = undefined,
319        offset: usize = undefined,
320        co_prime: usize,
321
322        const Self = @This();
323
324        pub fn init(slice: []T, rng: std.Random) Self {
325            return Self{
326                .rng = rng,
327                .slice = slice,
328                .co_prime = blk: {
329                    if (slice.len == 0) break :blk 0;
330                    var prime = slice.len / 2;
331                    while (prime < slice.len) : (prime += 1) {
332                        var gcd = [_]usize{ prime, slice.len };
333                        while (gcd[1] != 0) {
334                            const temp = gcd;
335                            gcd = [_]usize{ temp[1], temp[0] % temp[1] };
336                        }
337                        if (gcd[0] == 1) break;
338                    }
339                    break :blk prime;
340                },
341            };
342        }
343
344        pub fn reset(self: *Self) void {
345            self.index = 0;
346            self.offset = self.rng.int(usize);
347        }
348
349        pub fn next(self: *Self) ?*T {
350            if (self.index >= self.slice.len) return null;
351            defer self.index += 1;
352            return &self.slice[((self.index *% self.co_prime) +% self.offset) % self.slice.len];
353        }
354    };
355}
356
357const TestTreap = Treap(u64, std.math.order);
358const TestNode = TestTreap.Node;
359
360test "insert, find, replace, remove" {
361    var treap = TestTreap{};
362    var nodes: [10]TestNode = undefined;
363
364    var prng = std.Random.DefaultPrng.init(0xdeadbeef);
365    var iter = SliceIterRandomOrder(TestNode).init(&nodes, prng.random());
366
367    // insert check
368    iter.reset();
369    while (iter.next()) |node| {
370        const key = prng.random().int(u64);
371
372        // make sure the current entry is empty.
373        var entry = treap.getEntryFor(key);
374        try testing.expectEqual(entry.key, key);
375        try testing.expectEqual(entry.node, null);
376
377        // insert the entry and make sure the fields are correct.
378        entry.set(node);
379        try testing.expectEqual(node.key, key);
380        try testing.expectEqual(entry.key, key);
381        try testing.expectEqual(entry.node, node);
382    }
383
384    // find check
385    iter.reset();
386    while (iter.next()) |node| {
387        const key = node.key;
388
389        // find the entry by-key and by-node after having been inserted.
390        const entry = treap.getEntryFor(node.key);
391        try testing.expectEqual(entry.key, key);
392        try testing.expectEqual(entry.node, node);
393        try testing.expectEqual(entry.node, treap.getEntryForExisting(node).node);
394    }
395
396    // in-order iterator check
397    {
398        var it = treap.inorderIterator();
399        var last_key: u64 = 0;
400        while (it.next()) |node| {
401            try std.testing.expect(node.key >= last_key);
402            last_key = node.key;
403        }
404    }
405
406    // replace check
407    iter.reset();
408    while (iter.next()) |node| {
409        const key = node.key;
410
411        // find the entry by node since we already know it exists
412        var entry = treap.getEntryForExisting(node);
413        try testing.expectEqual(entry.key, key);
414        try testing.expectEqual(entry.node, node);
415
416        var stub_node: TestNode = undefined;
417
418        // replace the node with a stub_node and ensure future finds point to the stub_node.
419        entry.set(&stub_node);
420        try testing.expectEqual(entry.node, &stub_node);
421        try testing.expectEqual(entry.node, treap.getEntryFor(key).node);
422        try testing.expectEqual(entry.node, treap.getEntryForExisting(&stub_node).node);
423
424        // replace the stub_node back to the node and ensure future finds point to the old node.
425        entry.set(node);
426        try testing.expectEqual(entry.node, node);
427        try testing.expectEqual(entry.node, treap.getEntryFor(key).node);
428        try testing.expectEqual(entry.node, treap.getEntryForExisting(node).node);
429    }
430
431    // remove check
432    iter.reset();
433    while (iter.next()) |node| {
434        const key = node.key;
435
436        // find the entry by node since we already know it exists
437        var entry = treap.getEntryForExisting(node);
438        try testing.expectEqual(entry.key, key);
439        try testing.expectEqual(entry.node, node);
440
441        // remove the node at the entry and ensure future finds point to it being removed.
442        entry.set(null);
443        try testing.expectEqual(entry.node, null);
444        try testing.expectEqual(entry.node, treap.getEntryFor(key).node);
445
446        // insert the node back and ensure future finds point to the inserted node
447        entry.set(node);
448        try testing.expectEqual(entry.node, node);
449        try testing.expectEqual(entry.node, treap.getEntryFor(key).node);
450        try testing.expectEqual(entry.node, treap.getEntryForExisting(node).node);
451
452        // remove the node again and make sure it was cleared after the insert
453        entry.set(null);
454        try testing.expectEqual(entry.node, null);
455        try testing.expectEqual(entry.node, treap.getEntryFor(key).node);
456    }
457}
458
459test "inorderIterator" {
460    var treap = TestTreap{};
461    var nodes: [10]TestNode = undefined;
462
463    // Build the tree.
464    var i: usize = 0;
465    while (i < 10) : (i += 1) {
466        const key = @as(u64, i);
467        var entry = treap.getEntryFor(key);
468        entry.set(&nodes[i]);
469    }
470
471    // Test the iterator.
472    var iter = treap.inorderIterator();
473    i = 0;
474    while (iter.next()) |node| {
475        const key = @as(u64, i);
476        try testing.expectEqual(key, node.key);
477        i += 1;
478    }
479}
480
481test "getMin, getMax, simple" {
482    var treap = TestTreap{};
483    var nodes: [3]TestNode = undefined;
484
485    try testing.expectEqual(null, treap.getMin());
486    try testing.expectEqual(null, treap.getMax());
487    { // nodes[1]
488        var entry = treap.getEntryFor(1);
489        entry.set(&nodes[1]);
490        try testing.expectEqual(&nodes[1], treap.getMin());
491        try testing.expectEqual(&nodes[1], treap.getMax());
492    }
493    { // nodes[0]
494        var entry = treap.getEntryFor(0);
495        entry.set(&nodes[0]);
496        try testing.expectEqual(&nodes[0], treap.getMin());
497        try testing.expectEqual(&nodes[1], treap.getMax());
498    }
499    { // nodes[2]
500        var entry = treap.getEntryFor(2);
501        entry.set(&nodes[2]);
502        try testing.expectEqual(&nodes[0], treap.getMin());
503        try testing.expectEqual(&nodes[2], treap.getMax());
504    }
505}
506
507test "getMin, getMax, random" {
508    var nodes: [100]TestNode = undefined;
509    var prng = std.Random.DefaultPrng.init(0xdeadbeef);
510    var iter = SliceIterRandomOrder(TestNode).init(&nodes, prng.random());
511
512    var treap = TestTreap{};
513    var min: u64 = std.math.maxInt(u64);
514    var max: u64 = 0;
515
516    try testing.expectEqual(null, treap.getMin());
517    try testing.expectEqual(null, treap.getMax());
518
519    // Insert and check min/max after each insertion.
520    iter.reset();
521    while (iter.next()) |node| {
522        const key = prng.random().int(u64);
523
524        // Insert into `treap`.
525        var entry = treap.getEntryFor(key);
526        entry.set(node);
527
528        if (key < min) min = key;
529        if (key > max) max = key;
530
531        const min_node = treap.getMin().?;
532        try std.testing.expectEqual(null, min_node.prev());
533        try std.testing.expectEqual(min, min_node.key);
534
535        const max_node = treap.getMax().?;
536        try std.testing.expectEqual(null, max_node.next());
537        try std.testing.expectEqual(max, max_node.key);
538    }
539}
540
541test "node.{prev(),next()} with sequential insertion and deletion" {
542    // Insert order: 50, 0, 1, 2, ..., 49, 51, 52, ..., 99.
543    // Delete order: 0, 1, 2, ..., 49, 51, 52, ..., 99.
544    // Check 50's neighbors.
545    var treap = TestTreap{};
546    var nodes: [100]TestNode = undefined;
547    {
548        var entry = treap.getEntryFor(50);
549        entry.set(&nodes[50]);
550        try testing.expectEqual(50, nodes[50].key);
551        try testing.expectEqual(null, nodes[50].prev());
552        try testing.expectEqual(null, nodes[50].next());
553    }
554    // Insert others.
555    var i: usize = 0;
556    while (i < 50) : (i += 1) {
557        const key = @as(u64, i);
558        const node = &nodes[i];
559        var entry = treap.getEntryFor(key);
560        entry.set(node);
561        try testing.expectEqual(key, node.key);
562        try testing.expectEqual(node, nodes[50].prev());
563        try testing.expectEqual(null, nodes[50].next());
564    }
565    i = 51;
566    while (i < 100) : (i += 1) {
567        const key = @as(u64, i);
568        const node = &nodes[i];
569        var entry = treap.getEntryFor(key);
570        entry.set(node);
571        try testing.expectEqual(key, node.key);
572        try testing.expectEqual(&nodes[49], nodes[50].prev());
573        try testing.expectEqual(&nodes[51], nodes[50].next());
574    }
575    // Remove others.
576    i = 0;
577    while (i < 49) : (i += 1) {
578        const key = @as(u64, i);
579        var entry = treap.getEntryFor(key);
580        entry.set(null);
581        try testing.expectEqual(&nodes[49], nodes[50].prev());
582        try testing.expectEqual(&nodes[51], nodes[50].next());
583    }
584    { // i = 49.
585        const key = @as(u64, i);
586        var entry = treap.getEntryFor(key);
587        entry.set(null);
588        try testing.expectEqual(null, nodes[50].prev());
589        try testing.expectEqual(&nodes[51], nodes[50].next());
590    }
591    i = 51;
592    while (i < 99) : (i += 1) {
593        const key = @as(u64, i);
594        var entry = treap.getEntryFor(key);
595        entry.set(null);
596        try testing.expectEqual(null, nodes[50].prev());
597        try testing.expectEqual(&nodes[i + 1], nodes[50].next());
598    }
599    { // i = 99.
600        const key = @as(u64, i);
601        var entry = treap.getEntryFor(key);
602        entry.set(null);
603        try testing.expectEqual(null, nodes[50].prev());
604        try testing.expectEqual(null, nodes[50].next());
605    }
606}
607
608fn findFirstGreaterOrEqual(array: []u64, value: u64) usize {
609    var i: usize = 0;
610    while (i < array.len and array[i] < value) i += 1;
611    return i;
612}
613
614fn testOrderedArrayAndTreapConsistency(array: []u64, treap: *TestTreap) !void {
615    var i: usize = 0;
616    while (i < array.len) : (i += 1) {
617        const value = array[i];
618
619        const entry = treap.getEntryFor(value);
620        try testing.expect(entry.node != null);
621        const node = entry.node.?;
622        try testing.expectEqual(value, node.key);
623
624        if (i == 0) {
625            try testing.expectEqual(node.prev(), null);
626        } else {
627            try testing.expectEqual(node.prev(), treap.getEntryFor(array[i - 1]).node);
628        }
629        if (i + 1 == array.len) {
630            try testing.expectEqual(node.next(), null);
631        } else {
632            try testing.expectEqual(node.next(), treap.getEntryFor(array[i + 1]).node);
633        }
634    }
635}
636
637test "node.{prev(),next()} with random data" {
638    var nodes: [100]TestNode = undefined;
639    var prng = std.Random.DefaultPrng.init(0xdeadbeef);
640    var iter = SliceIterRandomOrder(TestNode).init(&nodes, prng.random());
641
642    var treap = TestTreap{};
643    // A slow, stupid but correct reference. Ordered.
644    var golden = std.array_list.Managed(u64).init(std.testing.allocator);
645    defer golden.deinit();
646
647    // Insert.
648    iter.reset();
649    while (iter.next()) |node| {
650        const key = prng.random().int(u64);
651
652        // Insert into `golden`.
653        const i = findFirstGreaterOrEqual(golden.items, key);
654        // Ensure not found. If found: `prng`'s fault.
655        try testing.expect(i == golden.items.len or golden.items[i] > key);
656        try golden.insert(i, key);
657
658        // Insert into `treap`.
659        var entry = treap.getEntryFor(key);
660        entry.set(node);
661
662        try testOrderedArrayAndTreapConsistency(golden.items, &treap);
663    }
664
665    // Delete.
666    iter.reset();
667    while (iter.next()) |node| {
668        const key = node.key;
669
670        // Delete from `golden`.
671        const i = findFirstGreaterOrEqual(golden.items, key);
672        try testing.expect(i < golden.items.len);
673        _ = golden.orderedRemove(i);
674
675        // Delete from `treap`.
676        var entry = treap.getEntryFor(key);
677        try testing.expect(entry.node != null);
678        entry.set(null);
679
680        try testOrderedArrayAndTreapConsistency(golden.items, &treap);
681    }
682}