i think it works!!!

This commit is contained in:
Janis 2023-03-20 16:19:54 +01:00
parent 0ee791db3c
commit aca2c7241b

View file

@ -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 { fn insert(self: *Self, value: u32) !void {
if (self.root) |*root| { if (self.get_root()) |*root| {
const search = root.find_key(value); const search = root.find_key(value);
switch (search) { switch (search) {
@ -192,7 +204,7 @@ const BTree = struct {
} }
fn remove(self: *Self, key: u32) void { fn remove(self: *Self, key: u32) void {
if (self.root) |*root| { if (self.get_root()) |*root| {
const search = root.find_key(key); const search = root.find_key(key);
switch (search) { switch (search) {
@ -205,7 +217,7 @@ const BTree = struct {
} }
fn find_key(self: *Self, key: u32) ?u32 { fn find_key(self: *Self, key: u32) ?u32 {
switch (self.root.?.find_key(key)) { switch (self.get_root().?.find_key(key)) {
.Leaf => |leaf| { .Leaf => |leaf| {
return leaf.leaf.get_values()[leaf.idx]; return leaf.leaf.get_values()[leaf.idx];
}, },
@ -216,14 +228,14 @@ const BTree = struct {
} }
fn dbg(self: *Self) void { fn dbg(self: *Self) void {
if (self.root) |root| { if (self.get_root()) |root| {
root.dbg(); root.dbg();
std.debug.print("\n", .{}); std.debug.print("\n", .{});
} }
} }
fn destroy(self: *Self) void { fn destroy(self: *Self) void {
if (self.root) |*root| { if (self.get_root()) |*root| {
root.destroy(); root.destroy();
} }
} }
@ -360,7 +372,6 @@ const BTree = struct {
fn remove_key_from_node(self: NodeOrLeaf, key: u32) void { fn remove_key_from_node(self: NodeOrLeaf, key: u32) void {
switch (self.force()) { switch (self.force()) {
.internal => |node| { .internal => |node| {
//const Option = Optional.Option;
// need to check if the edges to the left and right of the to-be-removed key exist, // 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 // and if both exist, find the immediate neighbors of the key and promote
// the one in the bigger leaf up as a replacement. // the one in the bigger leaf up as a replacement.
@ -644,6 +655,7 @@ const BTree = struct {
if (edg) |edge| { if (edg) |edge| {
edge.as_leaf().set_parent(self, @intCast(u16, i - count)); edge.as_leaf().set_parent(self, @intCast(u16, i - count));
self.edges[i - count] = edge; 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 { fn set_parent(self: *Leaf, parent: *Node, idx: u16) void {
if (idx < 0 or idx > parent.leaf.len or idx > CAPACITY) { 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 }; 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 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: { const sibling: struct { node: NodeOrLeaf, side: Side } = blk: {
switch (left_sib) { switch (left_sib) {
@ -851,24 +883,28 @@ const BTree = struct {
} }
}; };
const offset = @intCast(i32, sibling.node.as_leaf().parent.?.idx) - @intCast(i32, parent.idx); if (parent.parent != sibling.node.as_leaf().parent.?.parent) {
std.debug.print("{any} {} {} {}\n", .{ sibling.node.as_leaf().parent, sibling.node.as_leaf().parent.?.idx, parent.idx, offset }); 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) { if (sibling.node.as_leaf().len > MIN_AFTER_SPLIT) {
// rotate // rotate value from sibling -> parent -> self
const index = @intCast(usize, @max(0, parent.idx + offset)); const index = @intCast(usize, sibling.side.parent_seperator_idx(parent.idx));
std.debug.print("{} {} {}\n", .{ parent.idx, offset, index });
NodeOrLeaf.from_leaf(self).push_value(parent.parent.leaf.values[index]); NodeOrLeaf.from_leaf(self).push_value(parent.parent.leaf.values[index]);
parent.parent.leaf.values[index] = blk: { parent.parent.leaf.values[index] = blk: {
if (offset < 0) { switch (sibling.side) {
.Left => {
const value = sibling.node.get_most_significant_value(); const value = sibling.node.get_most_significant_value();
sibling.node.as_leaf().remove_key(value); sibling.node.as_leaf().remove_key(value);
break :blk value; break :blk value;
} else { },
.Right => {
const value = sibling.node.get_least_significant_value(); const value = sibling.node.get_least_significant_value();
sibling.node.as_leaf().remove_key(value); sibling.node.as_leaf().remove_key(value);
break :blk value; break :blk value;
},
} }
}; };
@ -876,11 +912,23 @@ const BTree = struct {
switch (NodeOrLeaf.from_leaf(self)) { switch (NodeOrLeaf.from_leaf(self)) {
.internal => |iself| { .internal => |iself| {
const isibling = sibling.node.internal; 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 => {}, .leaf => {},
} }
@ -897,14 +945,14 @@ const BTree = struct {
defer right.destroy(); defer right.destroy();
// remove superfluous parent edge to right
_ = parent.parent.remove_edge(right.parent.?.idx);
// merge parent seperator into left // merge parent seperator into left
const key = parent.parent.leaf.get_value(left.parent.?.idx); const key = parent.parent.leaf.get_value(left.parent.?.idx);
parent.parent.leaf.remove_key(key); parent.parent.leaf.remove_key(key);
NodeOrLeaf.from_leaf(left).push_value(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 // copy values from right to left
std.mem.copy(u32, left.values[left.len..], right.values[0..right.len]); std.mem.copy(u32, left.values[left.len..], right.values[0..right.len]);
@ -913,7 +961,7 @@ const BTree = struct {
.internal => |ileft| { .internal => |ileft| {
const iright = @ptrCast(*Node, right); 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| { for (ileft.get_edges(), 0..) |e, i| {
if (e) |ee| { if (e) |ee| {
@ -938,6 +986,7 @@ const BTree = struct {
// copy values // copy values
root.as_leaf().len = edge.as_leaf().len; root.as_leaf().len = edge.as_leaf().len;
root.as_leaf().level = edge.as_leaf().level; 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..]); std.mem.copy(u32, root.leaf.values[0..], edge.as_leaf().values[0..]);
switch (edge.force()) { switch (edge.force()) {
@ -1129,7 +1178,7 @@ test "btree rand insert" {
tree.dbg(); tree.dbg();
} }
test "ref removal" { test "ref removal left" {
std.debug.print("remove keys\n", .{}); std.debug.print("remove keys\n", .{});
var tree = BTree.create(std.testing.allocator); var tree = BTree.create(std.testing.allocator);
@ -1144,6 +1193,51 @@ test "ref removal" {
for (0..15) |i| { for (0..15) |i| {
tree.remove(@intCast(u32, 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(); tree.dbg();