mirror of
https://github.com/rdmsr/zag.git
synced 2026-10-30 23:08:21 +00:00
all: tidy
This commit is contained in:
+50
-29
@@ -1,4 +1,4 @@
|
||||
//! AVL tree implementation
|
||||
//! AVL tree impLementation
|
||||
//! Invariant: For every node, the difference in height between its left
|
||||
//! and right subtrees is strictly limited to -1, 0 or 1.
|
||||
const bst = @import("bst.zig");
|
||||
@@ -12,26 +12,28 @@ const zero: u2 = 0;
|
||||
const one: u2 = 2;
|
||||
|
||||
fn get_bf(node: *bst.Node) u2 {
|
||||
return node.parent.get_tag();
|
||||
return node.parent.tag();
|
||||
}
|
||||
|
||||
fn set_bf(node: *bst.Node, bf: u2) void {
|
||||
node.parent.set_tag(bf);
|
||||
}
|
||||
|
||||
pub fn AVLTree(comptime cmp: fn (*const bst.Node, *const bst.Node) std.math.Order) type {
|
||||
pub fn AVLTree(
|
||||
comptime cmp: fn (*const bst.Node, *const bst.Node) std.math.Order,
|
||||
) type {
|
||||
return struct {
|
||||
tree: bst.BST(cmp),
|
||||
|
||||
const Self = @This();
|
||||
const Tree = @This();
|
||||
|
||||
pub fn init() Self {
|
||||
return Self{
|
||||
pub fn init() Tree {
|
||||
return Tree{
|
||||
.tree = bst.BST(cmp).init(),
|
||||
};
|
||||
}
|
||||
|
||||
fn rotate_left(self: *Self, x: *bst.Node, z: *bst.Node) *bst.Node {
|
||||
fn rotate_left(self: *Tree, x: *bst.Node, z: *bst.Node) *bst.Node {
|
||||
x.right = z.left;
|
||||
|
||||
if (!self.tree.is_nil(z.left)) {
|
||||
@@ -53,7 +55,7 @@ pub fn AVLTree(comptime cmp: fn (*const bst.Node, *const bst.Node) std.math.Orde
|
||||
return z;
|
||||
}
|
||||
|
||||
fn rotate_right(self: *Self, x: *bst.Node, z: *bst.Node) *bst.Node {
|
||||
fn rotate_right(self: *Tree, x: *bst.Node, z: *bst.Node) *bst.Node {
|
||||
x.left = z.right;
|
||||
|
||||
if (!self.tree.is_nil(z.right)) {
|
||||
@@ -75,7 +77,11 @@ pub fn AVLTree(comptime cmp: fn (*const bst.Node, *const bst.Node) std.math.Orde
|
||||
return z;
|
||||
}
|
||||
|
||||
fn rotate_right_left(self: *Self, x: *bst.Node, z: *bst.Node) *bst.Node {
|
||||
fn rotate_right_left(
|
||||
self: *Tree,
|
||||
x: *bst.Node,
|
||||
z: *bst.Node,
|
||||
) *bst.Node {
|
||||
var y = z.left;
|
||||
var t2 = y.right;
|
||||
|
||||
@@ -123,7 +129,11 @@ pub fn AVLTree(comptime cmp: fn (*const bst.Node, *const bst.Node) std.math.Orde
|
||||
return y;
|
||||
}
|
||||
|
||||
fn rotate_left_right(self: *Self, x: *bst.Node, z: *bst.Node) *bst.Node {
|
||||
fn rotate_left_right(
|
||||
self: *Tree,
|
||||
x: *bst.Node,
|
||||
z: *bst.Node,
|
||||
) *bst.Node {
|
||||
var y = z.right;
|
||||
var t2 = y.left;
|
||||
|
||||
@@ -172,9 +182,14 @@ pub fn AVLTree(comptime cmp: fn (*const bst.Node, *const bst.Node) std.math.Orde
|
||||
}
|
||||
|
||||
/// Insert the node `elem` into the tree.
|
||||
pub fn insert(self: *Self, elem: *bst.Node) !void {
|
||||
pub fn insert(self: *Tree, elem: *bst.Node) !void {
|
||||
if (self.tree.is_empty()) {
|
||||
self.tree.insert(elem) catch unreachable;
|
||||
self.tree.insert(elem) catch {
|
||||
// This can't ever error since the tree is empty, so the
|
||||
// element can't already exist.
|
||||
unreachable;
|
||||
};
|
||||
|
||||
set_bf(elem, zero);
|
||||
return;
|
||||
}
|
||||
@@ -188,17 +203,18 @@ pub fn AVLTree(comptime cmp: fn (*const bst.Node, *const bst.Node) std.math.Orde
|
||||
|
||||
// Now the tree may be unbalanced, rebalance it.
|
||||
var node = elem;
|
||||
var parent = elem.parent.get_ptr();
|
||||
var parent = elem.parent.ptr();
|
||||
var n = &bst.nil;
|
||||
|
||||
while (!self.tree.is_nil(parent)) : (parent = parent.parent.get_ptr()) {
|
||||
const orig_parent = parent.parent.get_ptr();
|
||||
while (!self.tree.is_nil(parent)) : (parent = parent.parent.ptr()) {
|
||||
const orig_parent = parent.parent.ptr();
|
||||
|
||||
if (node == parent.right) {
|
||||
if (get_bf(parent) == one) {
|
||||
// This node has been inserted on the right of the parent,
|
||||
// and the parent already has a balance factor of 1 (right-heavy),
|
||||
// the parent's BF would then become +2, which breaks the invariant.
|
||||
// This node has been inserted on the right of the
|
||||
// parent, and the parent already has a balance factor
|
||||
// of 1 (right-heavy), the parent's BF would then
|
||||
// become +2, which breaks the invariant.
|
||||
// We need to rebalance.
|
||||
|
||||
if (get_bf(node) == minus_one) {
|
||||
@@ -214,13 +230,16 @@ pub fn AVLTree(comptime cmp: fn (*const bst.Node, *const bst.Node) std.math.Orde
|
||||
// 2
|
||||
// / \
|
||||
// 1 3
|
||||
// In the code, `parent` would be 1 and `node` would be 2
|
||||
// In the code, `parent` would be 1 and `node` would
|
||||
// be 2
|
||||
n = self.rotate_left(parent, node);
|
||||
}
|
||||
} else {
|
||||
// The balance factor is either 0 or -1, increase it.
|
||||
// If it was -1, now it is 0 so the subtree is perfectly balanced, we can stop.
|
||||
// If it was 0, now it is +1, so we may need to check higher up for imbalances.
|
||||
// If it was -1, now it is 0 so the subtree is
|
||||
// perfectly balanced, we can stop.
|
||||
// If it was 0, now it is +1, so we may need to check
|
||||
// higher up for imbalances.
|
||||
|
||||
if (get_bf(parent) == minus_one) {
|
||||
set_bf(parent, zero);
|
||||
@@ -236,9 +255,10 @@ pub fn AVLTree(comptime cmp: fn (*const bst.Node, *const bst.Node) std.math.Orde
|
||||
// The logic is the same as the other case but inverted.
|
||||
else {
|
||||
if (get_bf(parent) == minus_one) {
|
||||
// This node has been inserted on the left of the parent,
|
||||
// and the parent already has a balance factor of -1 (left-heavy),
|
||||
// the parent's balance factor would then become -2, which breaks the invariant.
|
||||
// This node has been inserted on the left of the
|
||||
// parent, and the parent already has a balance factor
|
||||
// of -1 (left-heavy), the parent's balance factor would
|
||||
// then become -2, which breaks the invariant.
|
||||
// We need to rebalance.
|
||||
|
||||
if (get_bf(node) == one) {
|
||||
@@ -276,10 +296,10 @@ pub fn AVLTree(comptime cmp: fn (*const bst.Node, *const bst.Node) std.math.Orde
|
||||
}
|
||||
|
||||
/// Delete the node `elem` from the tree.
|
||||
pub fn delete(self: *Self, elem: *bst.Node) void {
|
||||
pub fn delete(self: *Tree, elem: *bst.Node) void {
|
||||
var node = elem;
|
||||
var original_parent = &bst.nil;
|
||||
var parent = node.parent.get_ptr();
|
||||
var parent = node.parent.ptr();
|
||||
var was_on_left = !self.tree.is_nil(parent) and parent.left == node;
|
||||
var b = zero;
|
||||
|
||||
@@ -289,7 +309,7 @@ pub fn AVLTree(comptime cmp: fn (*const bst.Node, *const bst.Node) std.math.Orde
|
||||
self.tree.transplant(elem, elem.left);
|
||||
} else {
|
||||
var succ = self.tree.successor(node);
|
||||
parent = succ.parent.get_ptr();
|
||||
parent = succ.parent.ptr();
|
||||
was_on_left = !self.tree.is_nil(parent) and succ == parent.left;
|
||||
|
||||
if (parent != elem) {
|
||||
@@ -297,7 +317,8 @@ pub fn AVLTree(comptime cmp: fn (*const bst.Node, *const bst.Node) std.math.Orde
|
||||
succ.right = elem.right;
|
||||
succ.right.parent.set_ptr(succ);
|
||||
} else {
|
||||
// The successor is the direct child, so start rebalancing from it.
|
||||
// The successor is the direct child, so start rebalancing
|
||||
// from it.
|
||||
parent = succ;
|
||||
}
|
||||
|
||||
@@ -311,7 +332,7 @@ pub fn AVLTree(comptime cmp: fn (*const bst.Node, *const bst.Node) std.math.Orde
|
||||
|
||||
// Rebalance the tree.
|
||||
while (!self.tree.is_nil(parent)) {
|
||||
original_parent = parent.parent.get_ptr();
|
||||
original_parent = parent.parent.ptr();
|
||||
|
||||
if (node == parent.left or was_on_left) {
|
||||
was_on_left = false;
|
||||
|
||||
Reference in New Issue
Block a user