241 lines
5.8 KiB
Go
241 lines
5.8 KiB
Go
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()
|
|
}
|