| ... | @@ -51,26 +51,53 @@ pub fn Treap(comptime Key: type, comptime compareFn: anytype) type { | ... | @@ -51,26 +51,53 @@ pub fn Treap(comptime Key: type, comptime compareFn: anytype) type { |
| 51 | priority: usize, | 51 | priority: usize, |
| 52 | parent: ?*Node, | 52 | parent: ?*Node, |
| 53 | children: [2]?*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 | } |
| 54 | }; | 61 | }; |
| 55 | | 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 | |
| 56 | /// Returns the smallest Node by key in the treap if there is one. | 89 | /// Returns the smallest Node by key in the treap if there is one. |
| 57 | /// Use `getEntryForExisting()` to replace/remove this Node from the treap. | 90 | /// Use `getEntryForExisting()` to replace/remove this Node from the treap. |
| 58 | pub fn getMin(self: Self) ?*Node { | 91 | pub fn getMin(self: Self) ?*Node { |
| 59 | var node = self.root; | 92 | if (self.root) |root| return extremeInSubtreeOnDirection(root, 0); |
| 60 | while (node) |current| { | 93 | return null; |
| 61 | node = current.children[0] orelse break; | | |
| 62 | } | | |
| 63 | return node; | | |
| 64 | } | 94 | } |
| 65 | | 95 | |
| 66 | /// Returns the largest Node by key in the treap if there is one. | 96 | /// Returns the largest Node by key in the treap if there is one. |
| 67 | /// Use `getEntryForExisting()` to replace/remove this Node from the treap. | 97 | /// Use `getEntryForExisting()` to replace/remove this Node from the treap. |
| 68 | pub fn getMax(self: Self) ?*Node { | 98 | pub fn getMax(self: Self) ?*Node { |
| 69 | var node = self.root; | 99 | if (self.root) |root| return extremeInSubtreeOnDirection(root, 1); |
| 70 | while (node) |current| { | 100 | return null; |
| 71 | node = current.children[1] orelse break; | | |
| 72 | } | | |
| 73 | return node; | | |
| 74 | } | 101 | } |
| 75 | | 102 | |
| 76 | /// Lookup the Entry for the given key in the treap. | 103 | /// Lookup the Entry for the given key in the treap. |
| ... | @@ -117,7 +144,8 @@ pub fn Treap(comptime Key: type, comptime compareFn: anytype) type { | ... | @@ -117,7 +144,8 @@ pub fn Treap(comptime Key: type, comptime compareFn: anytype) type { |
| 117 | removed, | 144 | removed, |
| 118 | }, | 145 | }, |
| 119 | | 146 | |
| 120 | /// Update's the Node at this Entry in the treap with the new node. | 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. |
| 121 | pub fn set(self: *Entry, new_node: ?*Node) void { | 149 | pub fn set(self: *Entry, new_node: ?*Node) void { |
| 122 | // Update the entry's node reference after updating the treap below. | 150 | // Update the entry's node reference after updating the treap below. |
| 123 | defer self.node = new_node; | 151 | defer self.node = new_node; |
| ... | @@ -257,46 +285,26 @@ pub fn Treap(comptime Key: type, comptime compareFn: anytype) type { | ... | @@ -257,46 +285,26 @@ pub fn Treap(comptime Key: type, comptime compareFn: anytype) type { |
| 257 | link.* = target; | 285 | link.* = target; |
| 258 | } | 286 | } |
| 259 | | 287 | |
| | 288 | /// Usage example: |
| | 289 | /// var iter = treap.inorderIterator(); |
| | 290 | /// while (iter.next()) |node| { |
| | 291 | /// ... |
| | 292 | /// } |
| 260 | pub const InorderIterator = struct { | 293 | pub const InorderIterator = struct { |
| 261 | current: ?*Node, | 294 | current: ?*Node, |
| 262 | previous: ?*Node = null, | | |
| 263 | | 295 | |
| 264 | pub fn next(it: *InorderIterator) ?*Node { | 296 | pub fn next(it: *InorderIterator) ?*Node { |
| 265 | while (true) { | 297 | const current = it.current; |
| 266 | if (it.current) |current| { | 298 | it.current = if (current) |cur| |
| 267 | const previous = it.previous; | 299 | cur.next() |
| 268 | it.previous = current; | 300 | else |
| 269 | if (previous == current.parent) { | 301 | null; |
| 270 | if (current.children[0]) |left_child| { | 302 | return current; |
| 271 | it.current = left_child; | | |
| 272 | } else { | | |
| 273 | if (current.children[1]) |right_child| { | | |
| 274 | it.current = right_child; | | |
| 275 | } else { | | |
| 276 | it.current = current.parent; | | |
| 277 | } | | |
| 278 | return current; | | |
| 279 | } | | |
| 280 | } else if (previous == current.children[0]) { | | |
| 281 | if (current.children[1]) |right_child| { | | |
| 282 | it.current = right_child; | | |
| 283 | } else { | | |
| 284 | it.current = current.parent; | | |
| 285 | } | | |
| 286 | return current; | | |
| 287 | } else { | | |
| 288 | std.debug.assert(previous == current.children[1]); | | |
| 289 | it.current = current.parent; | | |
| 290 | } | | |
| 291 | } else { | | |
| 292 | return null; | | |
| 293 | } | | |
| 294 | } | | |
| 295 | } | 303 | } |
| 296 | }; | 304 | }; |
| 297 | | 305 | |
| 298 | pub fn inorderIterator(self: *Self) InorderIterator { | 306 | pub fn inorderIterator(self: *Self) InorderIterator { |
| 299 | return .{ .current = self.root }; | 307 | return .{ .current = self.getMin() }; |
| 300 | } | 308 | } |
| 301 | }; | 309 | }; |
| 302 | } | 310 | } |
| ... | @@ -447,3 +455,228 @@ test "insert, find, replace, remove" { | ... | @@ -447,3 +455,228 @@ test "insert, find, replace, remove" { |
| 447 | try testing.expectEqual(entry.node, treap.getEntryFor(key).node); | 455 | try testing.expectEqual(entry.node, treap.getEntryFor(key).node); |
| 448 | } | 456 | } |
| 449 | } | 457 | } |
| | 458 | |
| | 459 | test "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 | |
| | 481 | test "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 | |
| | 507 | test "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 | |
| | 541 | test "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 | |
| | 608 | fn 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 | |
| | 614 | fn 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 | |
| | 637 | test "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.ArrayList(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 | } |