i think it works!!!
This commit is contained in:
parent
0ee791db3c
commit
aca2c7241b
154
src/main.zig
154
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 {
|
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) {
|
||||||
const value = sibling.node.get_most_significant_value();
|
.Left => {
|
||||||
sibling.node.as_leaf().remove_key(value);
|
const value = sibling.node.get_most_significant_value();
|
||||||
break :blk value;
|
sibling.node.as_leaf().remove_key(value);
|
||||||
} else {
|
break :blk value;
|
||||||
const value = sibling.node.get_least_significant_value();
|
},
|
||||||
sibling.node.as_leaf().remove_key(value);
|
.Right => {
|
||||||
break :blk value;
|
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)) {
|
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();
|
||||||
|
|
Loading…
Reference in a new issue