This commit is contained in:
2026-07-20 19:57:25 +08:00
parent 4fa78d4c00
commit 124ad9afdf
26 changed files with 2715 additions and 5 deletions
+243
View File
@@ -0,0 +1,243 @@
package avl
import "cmp"
// avl.go
// 泛型 AVL 自平衡二叉搜索树。
//
// 约定:空子树高度为 0,叶子高度为 1;不插入重复值。
// 每次插入或删除后,都要更新 Height,再按 LL/LR/RR/RL 四种情况重平衡。
// AVLNode AVL 树节点。Height 是以该节点为根的子树高度。
type AVLNode[T cmp.Ordered] struct {
Val T
Left *AVLNode[T]
Right *AVLNode[T]
Height int
}
// AVLTree AVL 自平衡二叉搜索树。
type AVLTree[T cmp.Ordered] struct {
Root *AVLNode[T]
}
// NewAVLTree 创建一棵空 AVL 树。
func NewAVLTree[T cmp.Ordered]() *AVLTree[T] {
return &AVLTree[T]{}
}
// Insert 插入 v;重复值不插入。
func (t *AVLTree[T]) Insert(v T) {
var insert func(node *AVLNode[T]) *AVLNode[T]
insert = func(node *AVLNode[T]) *AVLNode[T] {
if node == nil {
return &AVLNode[T]{Val: v, Height: 1}
}
if v == node.Val {
return node
} else if v < node.Val {
node.Left = insert(node.Left)
} else {
node.Right = insert(node.Right)
}
node.Height = t.calculateHeight(node)
return t.balancing(node)
}
t.Root = insert(t.Root)
}
func (t *AVLTree[T]) balancing(node *AVLNode[T]) *AVLNode[T] {
bf := t.calculateBF(node)
if bf < -1 {
// 右重 R
_bf := t.calculateBF(node.Right)
if _bf <= 0 {
// RR:左旋自身
return t.rotateLeft(node)
}
if _bf > 0 {
// RL: 右旋右孩子再左旋自身
node.Right = t.rotateRight(node.Right)
return t.rotateLeft(node)
}
}
if bf > 1 {
// 左重 L
_bf := t.calculateBF(node.Left)
if _bf >= 0 {
// LL: 右旋自身
return t.rotateRight(node)
}
if _bf < 0 {
// LR: 左旋左孩子再右旋自身
node.Left = t.rotateLeft(node.Left)
return t.rotateRight(node)
}
}
return node
}
func (t *AVLTree[T]) calculateHeight(node *AVLNode[T]) int {
if node == nil {
return 0
}
l, r := 0, 0
if node.Left != nil {
l = node.Left.Height
}
if node.Right != nil {
r = node.Right.Height
}
return max(l, r) + 1
}
func (t *AVLTree[T]) calculateBF(node *AVLNode[T]) int {
if node == nil {
return 0
}
leftHeight, rightHeight := 0, 0
if node.Left != nil {
leftHeight = node.Left.Height
}
if node.Right != nil {
rightHeight = node.Right.Height
}
bf := leftHeight - rightHeight
return bf
}
// rotateLeft 对 node 左旋,返回旋转后的新子树根。
//
// node right
// / \ / \
// A right → node C
// / \ / \
// B C A B
//
// B 的值介于 node 和 right 之间,因此旋转后要接到 node.Right。
func (t *AVLTree[T]) rotateLeft(node *AVLNode[T]) *AVLNode[T] {
rNode := node.Right
node.Right = rNode.Left
rNode.Left = node
node.Height = t.calculateHeight(node)
rNode.Height = t.calculateHeight(rNode)
return rNode
}
// rotateRight 对 node 右旋,返回旋转后的新子树根。
//
// node left
// / \ / \
// left C → A node
// / \ / \
// A B B C
//
// B 的值介于 left 和 node 之间,因此旋转后要接到 node.Left。
func (t *AVLTree[T]) rotateRight(node *AVLNode[T]) *AVLNode[T] {
lNode := node.Left
node.Left = lNode.Right
lNode.Right = node
node.Height = t.calculateHeight(node)
lNode.Height = t.calculateHeight(lNode)
return lNode
}
func (t *AVLTree[T]) Inorder() []T {
res := []T{}
var helper func(node *AVLNode[T])
helper = func(node *AVLNode[T]) {
if node == nil {
return
}
helper(node.Left)
res = append(res, node.Val)
helper(node.Right)
}
helper(t.Root)
return res
}
// Search 查找 v 是否存在。只读操作,不需要更新高度或旋转。
func (t *AVLTree[T]) Search(v T) bool {
node := t.Root
for node != nil {
if node.Val == v {
return true
}
if v < node.Val {
node = node.Left
} else {
node = node.Right
}
}
return false
}
// Height 返回整棵树的高度;空树为 0。
func (t *AVLTree[T]) Height() int {
if t.Root == nil {
return 0
}
return t.Root.Height
}
// Min 返回最小值及其是否存在。
func (t *AVLTree[T]) Min() (T, bool) {
node := t.Root
if node == nil {
var zero T
return zero, false
}
for node.Left != nil {
node = node.Left
}
return node.Val, true
}
// Max 返回最大值及其是否存在。
func (t *AVLTree[T]) Max() (T, bool) {
node := t.Root
if node == nil {
var zero T
return zero, false
}
for node.Right != nil {
node = node.Right
}
return node.Val, true
}
// Delete 删除 v;若 v 不存在,树保持不变。
func (t *AVLTree[T]) Delete(v T) {
var deleteNode func(node *AVLNode[T], target T) *AVLNode[T]
deleteNode = func(node *AVLNode[T], target T) *AVLNode[T] {
if node == nil {
return nil
}
if target < node.Val {
node.Left = deleteNode(node.Left, target)
} else if target > node.Val {
node.Right = deleteNode(node.Right, target)
} else {
if node.Left == nil && node.Right != nil {
return node.Right
}
if node.Left != nil && node.Right == nil {
return node.Left
}
if node.Left != nil && node.Right != nil {
n := node.Right
for n.Left != nil {
n = n.Left
}
node.Val = n.Val
node.Right = deleteNode(node.Right, n.Val)
} else {
return nil
}
}
node.Height = t.calculateHeight(node)
return t.balancing(node)
}
t.Root = deleteNode(t.Root, v)
}
+189
View File
@@ -0,0 +1,189 @@
package avl
import (
"reflect"
"testing"
)
func TestAVLBasicOperations(t *testing.T) {
tree := NewAVLTree[int]()
if tree.Height() != 0 {
t.Fatalf("空树 Height() = %d, want 0", tree.Height())
}
if _, ok := tree.Min(); ok {
t.Fatal("空树 Min() 的 ok = true, want false")
}
if _, ok := tree.Max(); ok {
t.Fatal("空树 Max() 的 ok = true, want false")
}
if tree.Search(1) {
t.Fatal("空树 Search(1) = true, want false")
}
for _, v := range []int{6, 3, 2, 1, 4, 5} {
tree.Insert(v)
}
if got, want := tree.Inorder(), []int{1, 2, 3, 4, 5, 6}; !reflect.DeepEqual(got, want) {
t.Fatalf("Inorder() = %v, want %v", got, want)
}
if !tree.Search(1) || !tree.Search(6) || tree.Search(7) {
t.Fatalf("Search 结果不正确:Search(1)=%v, Search(6)=%v, Search(7)=%v", tree.Search(1), tree.Search(6), tree.Search(7))
}
if got, ok := tree.Min(); !ok || got != 1 {
t.Fatalf("Min() = (%d, %v), want (1, true)", got, ok)
}
if got, ok := tree.Max(); !ok || got != 6 {
t.Fatalf("Max() = (%d, %v), want (6, true)", got, ok)
}
assertAVL(t, tree.Root, nil, nil)
}
func TestAVLDelete(t *testing.T) {
cases := []struct {
name string
values []int
delete int
want []int
wantMin *int
wantMax *int
}{
{
name: "delete only root leaf",
values: []int{10},
delete: 10,
want: []int{},
},
{
name: "delete root with one child",
values: []int{10, 5},
delete: 10,
want: []int{5},
wantMin: intPtr(5),
wantMax: intPtr(5),
},
{
name: "delete non-root leaf and update parent height",
values: []int{10, 5, 15},
delete: 5,
want: []int{10, 15},
wantMin: intPtr(10),
wantMax: intPtr(15),
},
{
name: "delete non-root with one child",
values: []int{10, 5, 15, 12},
delete: 15,
want: []int{5, 10, 12},
wantMin: intPtr(5),
wantMax: intPtr(12),
},
{
name: "delete root with two children successor is leaf",
values: []int{10, 5, 15, 12, 18},
delete: 10,
want: []int{5, 12, 15, 18},
wantMin: intPtr(5),
wantMax: intPtr(18),
},
{
name: "delete root with two children successor has right child",
values: []int{10, 5, 20, 15, 25, 17},
delete: 10,
want: []int{5, 15, 17, 20, 25},
wantMin: intPtr(5),
wantMax: intPtr(25),
},
{
name: "delete missing value leaves tree unchanged",
values: []int{10, 5, 20, 15, 25},
delete: 99,
want: []int{5, 10, 15, 20, 25},
wantMin: intPtr(5),
wantMax: intPtr(25),
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
tree := NewAVLTree[int]()
for _, v := range tc.values {
tree.Insert(v)
}
tree.Delete(tc.delete)
if got := tree.Inorder(); !reflect.DeepEqual(got, tc.want) {
t.Fatalf("Delete(%d) 后 Inorder() = %v, want %v", tc.delete, got, tc.want)
}
if tree.Search(tc.delete) && tc.delete != 99 {
t.Fatalf("Delete(%d) 后 Search(%d) = true, want false", tc.delete, tc.delete)
}
if tc.wantMin == nil {
if tree.Height() != 0 {
t.Fatalf("删空树后 Height() = %d, want 0", tree.Height())
}
if _, ok := tree.Min(); ok {
t.Fatal("删空树后 Min() 的 ok = true, want false")
}
if _, ok := tree.Max(); ok {
t.Fatal("删空树后 Max() 的 ok = true, want false")
}
} else {
if got, ok := tree.Min(); !ok || got != *tc.wantMin {
t.Fatalf("Min() = (%d, %v), want (%d, true)", got, ok, *tc.wantMin)
}
if got, ok := tree.Max(); !ok || got != *tc.wantMax {
t.Fatalf("Max() = (%d, %v), want (%d, true)", got, ok, *tc.wantMax)
}
}
assertAVL(t, tree.Root, nil, nil)
})
}
}
func TestAVLDeleteRebalancesOnPathToRoot(t *testing.T) {
tree := NewAVLTree[int]()
for _, v := range []int{4, 2, 6, 1, 3, 5, 7} {
tree.Insert(v)
}
for _, v := range []int{7, 6, 5} {
tree.Delete(v)
assertAVL(t, tree.Root, nil, nil)
}
if got, want := tree.Inorder(), []int{1, 2, 3, 4}; !reflect.DeepEqual(got, want) {
t.Fatalf("连续删除后 Inorder() = %v, want %v", got, want)
}
}
func assertAVL(t *testing.T, node *AVLNode[int], lower, upper *int) int {
t.Helper()
if node == nil {
return 0
}
if lower != nil && node.Val <= *lower {
t.Fatalf("BST 性质被破坏:节点 %d <= 下界 %d", node.Val, *lower)
}
if upper != nil && node.Val >= *upper {
t.Fatalf("BST 性质被破坏:节点 %d >= 上界 %d", node.Val, *upper)
}
leftHeight := assertAVL(t, node.Left, lower, &node.Val)
rightHeight := assertAVL(t, node.Right, &node.Val, upper)
if balanceFactor := leftHeight - rightHeight; balanceFactor < -1 || balanceFactor > 1 {
t.Fatalf("节点 %d 的 BF = %d, want [-1, 1]", node.Val, balanceFactor)
}
wantHeight := max(leftHeight, rightHeight) + 1
if node.Height != wantHeight {
t.Fatalf("节点 %d 的 Height = %d, want %d", node.Val, node.Height, wantHeight)
}
return wantHeight
}
func intPtr(v int) *int {
return &v
}
+240
View File
@@ -0,0 +1,240 @@
package avl
import "fmt"
// AVL 自平衡二叉搜索树 —— 正确实现参考
//
// 核心设计点(对比你原文件里的 4 个 bug):
// 1. 节点维护 Height,平衡因子 BF = height(Left) - height(Right);合法范围 {-1,0,1}
// 2. 旋转函数【返回新子树根】,调用方用返回值接回父节点的 Left/Right
// —— 这解决了"旋转接不回去"的根本问题
// 3. 失衡判定看【子节点的 BF】,区分 LL/RR/LR/RL 四种 case,不是只看自己 BF
// 4. 不用全局 depthIncre flag,递归返回新根,height 直接从子节点算
type Node struct {
Val int
Left *Node
Right *Node
Height int // 以该节点为根的子树高度;空节点=0,叶子=1
}
func height(n *Node) int {
if n == nil {
return 0
}
return n.Height
}
func balanceFactor(n *Node) int {
if n == nil {
return 0
}
return height(n.Left) - height(n.Right)
}
func updateHeight(n *Node) {
l, r := height(n.Left), height(n.Right)
if l > r {
n.Height = l + 1
} else {
n.Height = r + 1
}
}
// 左旋:右子太重时,把右子 y 提上来,x 沉为 y 的左子
//
// x y
// / \ / \
// A y → x C
// / \ / \
// B C A B
//
// B 的值在 x、y 之间,必须留在中间 → 挂到 x 的右侧
func rotateLeft(x *Node) *Node {
y := x.Right
x.Right = y.Left
y.Left = x
updateHeight(x) // 先更新成为孩子的 x
updateHeight(y) // 再更新成为根的 y
return y
}
// 右旋:左子太重时,把左子 x 提上来,y 沉为 x 的右子
//
// y x
// / \ / \
// x C → A y
// / \ / \
// A B B C
//
// B 的值在 x、y 之间 → 挂到 y 的左侧
func rotateRight(y *Node) *Node {
x := y.Left
y.Left = x.Right
x.Right = y
updateHeight(y) // 先更新成为孩子的 y
updateHeight(x) // 再更新成为根的 x
return x
}
// 插入:递归返回新子树根
func Insert(root *Node, val int) *Node {
if root == nil {
return &Node{Val: val, Height: 1}
}
if val < root.Val {
root.Left = Insert(root.Left, val)
} else if val > root.Val {
root.Right = Insert(root.Right, val)
} else {
return root // 不允许重复值
}
updateHeight(root)
bf := balanceFactor(root)
// LL: 左子左重(左子 BF >= 0)→ 右旋一次
if bf > 1 && balanceFactor(root.Left) >= 0 {
return rotateRight(root)
}
// LR: 左子右重(左子 BF < 0)→ 先左旋左子,再右旋自己
if bf > 1 && balanceFactor(root.Left) < 0 {
root.Left = rotateLeft(root.Left)
return rotateRight(root)
}
// RR: 右子右重(右子 BF <= 0)→ 左旋一次
if bf < -1 && balanceFactor(root.Right) <= 0 {
return rotateLeft(root)
}
// RL: 右子左重(右子 BF > 0)→ 先右旋右子,再左旋自己
if bf < -1 && balanceFactor(root.Right) > 0 {
root.Right = rotateRight(root.Right)
return rotateLeft(root)
}
return root
}
// 删除:递归返回新子树根
func Delete(root *Node, val int) *Node {
if root == nil {
return nil
}
if val < root.Val {
root.Left = Delete(root.Left, val)
} else if val > root.Val {
root.Right = Delete(root.Right, val)
} else {
// 命中要删的节点
if root.Left == nil {
return root.Right
}
if root.Right == nil {
return root.Left
}
// 两子都在:用右子树最小值替换当前值,再删右子树里的那个最小值
minNode := root.Right
for minNode.Left != nil {
minNode = minNode.Left
}
root.Val = minNode.Val
root.Right = Delete(root.Right, minNode.Val)
}
updateHeight(root)
bf := balanceFactor(root)
// 重平衡逻辑与 Insert 完全一致(看子节点 BF 判 case)
if bf > 1 && balanceFactor(root.Left) >= 0 {
return rotateRight(root)
}
if bf > 1 && balanceFactor(root.Left) < 0 {
root.Left = rotateLeft(root.Left)
return rotateRight(root)
}
if bf < -1 && balanceFactor(root.Right) <= 0 {
return rotateLeft(root)
}
if bf < -1 && balanceFactor(root.Right) > 0 {
root.Right = rotateRight(root.Right)
return rotateLeft(root)
}
return root
}
func Search(root *Node, val int) bool {
for root != nil {
if val < root.Val {
root = root.Left
} else if val > root.Val {
root = root.Right
} else {
return true
}
}
return false
}
// 中序遍历 → 应得到升序序列(验证 BST 性质没被破坏)
func Inorder(root *Node, out *[]int) {
if root == nil {
return
}
Inorder(root.Left, out)
*out = append(*out, root.Val)
Inorder(root.Right, out)
}
func runAVLDemo() {
var root *Node
// 测试 1: 顺序插入 1..7(普通 BST 会退化成高度=7 的链表)
for _, v := range []int{1, 2, 3, 4, 5, 6, 7} {
root = Insert(root, v)
}
var arr []int
Inorder(root, &arr)
fmt.Println("顺序插入 1..7 中序遍历:", arr)
fmt.Printf("树高 = %d (普通BST会=7, AVL 应 ≤ 4)\n", height(root))
fmt.Println("Search 5:", Search(root, 5), "Search 99:", Search(root, 99))
// 测试 2: 乱序插入
root = nil
for _, v := range []int{5, 2, 8, 1, 9, 3, 7, 6, 4} {
root = Insert(root, v)
}
arr = nil
Inorder(root, &arr)
fmt.Println("\n乱序插入中序遍历:", arr)
fmt.Printf("树高 = %d\n", height(root))
// 测试 3: 删除
root = Delete(root, 5)
arr = nil
Inorder(root, &arr)
fmt.Println("删 5 后中序遍历:", arr)
fmt.Println("Search 5:", Search(root, 5))
fmt.Printf("树高 = %d\n", height(root))
// 测试 4: 验证所有 BF ∈ {-1,0,1}
if checkAllBF(root) {
fmt.Println("\n所有节点 |BF| ≤ 1 ✓")
}
}
// 验证整棵树每个节点的 |BF| ≤ 1
func checkAllBF(root *Node) bool {
var walk func(*Node) bool
walk = func(n *Node) bool {
if n == nil {
return true
}
bf := balanceFactor(n)
if bf < -1 || bf > 1 {
fmt.Printf("违反! 节点 %d 的 BF = %d\n", n.Val, bf)
return false
}
return walk(n.Left) && walk(n.Right)
}
return walk(root)
}
func main() {
runAVLDemo()
}