From aca2c7241b1ea1d3b7db1c1109f1e385975f8ef5 Mon Sep 17 00:00:00 2001 From: Janis Date: Mon, 20 Mar 2023 16:19:54 +0100 Subject: [PATCH] i think it works!!! --- src/main.zig | 154 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 124 insertions(+), 30 deletions(-) diff --git a/src/main.zig b/src/main.zig index 25a1a6f..7e6ce38 100644 --- a/src/main.zig +++ b/src/main.zig @@ -160,8 +160,20 @@ const BTree = struct { }; } + fn force_root(self: *Self) void { + if (self.root) |root| { + self.root = root.force(); + } + } + + fn get_root(self: *Self) ?NodeOrLeaf { + self.force_root(); + + return self.root; + } + fn insert(self: *Self, value: u32) !void { - if (self.root) |*root| { + if (self.get_root()) |*root| { const search = root.find_key(value); switch (search) { @@ -192,7 +204,7 @@ const BTree = struct { } fn remove(self: *Self, key: u32) void { - if (self.root) |*root| { + if (self.get_root()) |*root| { const search = root.find_key(key); switch (search) { @@ -205,7 +217,7 @@ const BTree = struct { } fn find_key(self: *Self, key: u32) ?u32 { - switch (self.root.?.find_key(key)) { + switch (self.get_root().?.find_key(key)) { .Leaf => |leaf| { return leaf.leaf.get_values()[leaf.idx]; }, @@ -216,14 +228,14 @@ const BTree = struct { } fn dbg(self: *Self) void { - if (self.root) |root| { + if (self.get_root()) |root| { root.dbg(); std.debug.print("\n", .{}); } } fn destroy(self: *Self) void { - if (self.root) |*root| { + if (self.get_root()) |*root| { root.destroy(); } } @@ -360,7 +372,6 @@ const BTree = struct { fn remove_key_from_node(self: NodeOrLeaf, key: u32) void { switch (self.force()) { .internal => |node| { - //const Option = Optional.Option; // need to check if the edges to the left and right of the to-be-removed key exist, // and if both exist, find the immediate neighbors of the key and promote // the one in the bigger leaf up as a replacement. @@ -644,6 +655,7 @@ const BTree = struct { if (edg) |edge| { edge.as_leaf().set_parent(self, @intCast(u16, i - count)); self.edges[i - count] = edge; + self.edges[i] = null; } } } @@ -733,7 +745,7 @@ const BTree = struct { fn set_parent(self: *Leaf, parent: *Node, idx: u16) void { if (idx < 0 or idx > parent.leaf.len or idx > CAPACITY) { - std.debug.print("{}", .{idx}); + std.debug.print("out of bounds parent idx {}", .{idx}); } self.parent = .{ .parent = parent, .idx = idx }; @@ -822,7 +834,27 @@ const BTree = struct { const right_sib = Optional.into_option(parent.parent.get_edge(parent.idx + 1)); - const Side = enum { Left, Right }; + const Side = enum { + Left, + Right, + fn to_offset(side: @This()) i32 { + return switch (side) { + .Left => -1, + .Right => 1, + }; + } + + // returns the index of the seperator in the parent where parent_idx is + // the index of the edge pointing to self, and side is the side on + // which the sibling was found + fn parent_seperator_idx(side: @This(), parent_idx: u16) u16 { + const offset: u16 = switch (side) { + .Left => 1, + .Right => 0, + }; + return parent_idx - offset; + } + }; const sibling: struct { node: NodeOrLeaf, side: Side } = blk: { switch (left_sib) { @@ -851,24 +883,28 @@ const BTree = struct { } }; - const offset = @intCast(i32, sibling.node.as_leaf().parent.?.idx) - @intCast(i32, parent.idx); - std.debug.print("{any} {} {} {}\n", .{ sibling.node.as_leaf().parent, sibling.node.as_leaf().parent.?.idx, parent.idx, offset }); + if (parent.parent != sibling.node.as_leaf().parent.?.parent) { + std.debug.print("ERROR parent: {}", .{parent.parent}); + std.debug.print("ERROR missmatching parents\n{}\n{}\n", .{ self, sibling.node.as_leaf() }); + } if (sibling.node.as_leaf().len > MIN_AFTER_SPLIT) { - // rotate - const index = @intCast(usize, @max(0, parent.idx + offset)); - std.debug.print("{} {} {}\n", .{ parent.idx, offset, index }); + // rotate value from sibling -> parent -> self + const index = @intCast(usize, sibling.side.parent_seperator_idx(parent.idx)); NodeOrLeaf.from_leaf(self).push_value(parent.parent.leaf.values[index]); parent.parent.leaf.values[index] = blk: { - if (offset < 0) { - const value = sibling.node.get_most_significant_value(); - sibling.node.as_leaf().remove_key(value); - break :blk value; - } else { - const value = sibling.node.get_least_significant_value(); - sibling.node.as_leaf().remove_key(value); - break :blk value; + switch (sibling.side) { + .Left => { + const value = sibling.node.get_most_significant_value(); + sibling.node.as_leaf().remove_key(value); + break :blk value; + }, + .Right => { + const value = sibling.node.get_least_significant_value(); + sibling.node.as_leaf().remove_key(value); + break :blk value; + }, } }; @@ -876,11 +912,23 @@ const BTree = struct { switch (NodeOrLeaf.from_leaf(self)) { .internal => |iself| { const isibling = sibling.node.internal; - iself.shift_edges_right(0, 1); - iself.edges[0] = isibling.edges[isibling.leaf.len]; - isibling.edges[isibling.leaf.len] = null; - iself.edges[0].?.as_leaf().set_parent(iself, 0); + switch (sibling.side) { + .Left => { + // shift self edges to the left because we are inserting + // siblings left most edge at self.edges[0] + iself.shift_edges_right(0, 1); + const edge = isibling.remove_edge(isibling.leaf.len); + edge.?.as_leaf().set_parent(iself, 0); + iself.edges[0] = edge; + }, + .Right => { + // here we simply append the edge to our own edges + const edge = isibling.remove_edge(0); + edge.?.as_leaf().set_parent(iself, iself.as_leaf().len); + iself.edges[iself.as_leaf().len] = edge; + }, + } }, .leaf => {}, } @@ -897,14 +945,14 @@ const BTree = struct { defer right.destroy(); + // remove superfluous parent edge to right + _ = parent.parent.remove_edge(right.parent.?.idx); + // merge parent seperator into left const key = parent.parent.leaf.get_value(left.parent.?.idx); parent.parent.leaf.remove_key(key); NodeOrLeaf.from_leaf(left).push_value(key); - // remove superfluous parent edge to right - _ = parent.parent.remove_edge(right.parent.?.idx); - // copy values from right to left std.mem.copy(u32, left.values[left.len..], right.values[0..right.len]); @@ -913,7 +961,7 @@ const BTree = struct { .internal => |ileft| { const iright = @ptrCast(*Node, right); - std.mem.copy(?NodeOrLeaf, ileft.edges[0..], iright.edges[0..]); + std.mem.copy(?NodeOrLeaf, ileft.edges[left.len + 1 ..], iright.edges[0 .. right.len + 1]); for (ileft.get_edges(), 0..) |e, i| { if (e) |ee| { @@ -938,6 +986,7 @@ const BTree = struct { // copy values root.as_leaf().len = edge.as_leaf().len; root.as_leaf().level = edge.as_leaf().level; + root.as_leaf().parent = null; std.mem.copy(u32, root.leaf.values[0..], edge.as_leaf().values[0..]); switch (edge.force()) { @@ -1129,7 +1178,7 @@ test "btree rand insert" { tree.dbg(); } -test "ref removal" { +test "ref removal left" { std.debug.print("remove keys\n", .{}); var tree = BTree.create(std.testing.allocator); @@ -1144,6 +1193,51 @@ test "ref removal" { for (0..15) |i| { tree.remove(@intCast(u32, i)); + tree.dbg(); + } + + tree.dbg(); + std.debug.print("\n", .{}); +} + +test "ref removal right" { + std.debug.print("remove keys\n", .{}); + + var tree = BTree.create(std.testing.allocator); + defer tree.destroy(); + + for (0..20) |i| { + _ = try tree.insert(@intCast(u32, i)); + } + + tree.dbg(); + std.debug.print("\n", .{}); + + for (0..15) |i| { + tree.remove(@intCast(u32, 20 - i)); + tree.dbg(); + } + + tree.dbg(); + std.debug.print("\n", .{}); +} + +test "ref removal middle" { + std.debug.print("remove keys\n", .{}); + + var tree = BTree.create(std.testing.allocator); + defer tree.destroy(); + + for (0..20) |i| { + _ = try tree.insert(@intCast(u32, i)); + } + + tree.dbg(); + std.debug.print("\n", .{}); + + for (0..10) |i| { + tree.remove(@intCast(u32, 15 - i)); + tree.dbg(); } tree.dbg();