平衡二叉树
- 概念
- 查找
- 插入
- 删除
1、概念
1.1 作用
防止 二叉搜索树 退化为链表,性能下降( O(logn)-->O(n) )
1.2 特征
- 树 为 二叉排序树
- 每个节点的左右高度差不超过2
- 二叉树的每个节点都处于平衡状态
1.3 定义
type AVLNode struct {
Val int // 节点值
Height int // 节点高度
Left *AVLNode // 左孩子
Right *AVLNode // 右孩子
}
2、查找操作
(与二叉搜索树相同)
// 查找元素
func (root *AVLNode) search(targer int) bool {
if root == nil {
return false
}
if root.Val > targer {
return root.Left.search(targer)
} else if root.Val < targer {
return root.Right.search(targer)
} else {
return true
}
}
3、插入操作
插入操作步骤:
- 找到对应位置插入
- 根据 树高 判断是否 平衡
- 若不平衡进行旋转操作
(引用:图解平衡二叉树平衡过程)
涉及函数:插入、获取树高、LL/RR/LR/RL
// 两者取最大
func max(a, b int) int {
if a > b {
return a
}
return b
}
// 获取当前节点的高度
func (root *AVLNode) getHeight() int {
if root == nil {
return 0
}
return max(root.Left.getHeight(), root.Right.getHeight()) + 1
}
// 左旋转 RR
func (root *AVLNode) leftRotate() *AVLNode {
tmp := root.Right
root.Right = tmp.Left
tmp.Left = root
root = tmp
root.Height = root.getHeight()
return root
}
// 右旋 LL
func (root *AVLNode) rightRotate() *AVLNode {
tmp := root.Left
root.Left = tmp.Right
tmp.Right = root
root = tmp
root.Height = root.getHeight()
return root
}
// 先左旋后右旋
func (root *AVLNode) LR_Rotate() *AVLNode {
root.Left = root.Left.leftRotate() // 左孩子先旋转 变为LL模式,再右旋转
return root.rightRotate()
}
// 先右旋后左旋
func (root *AVLNode) RL_Rotate() *AVLNode {
root.Right = root.Right.rightRotate()
return root.leftRotate()
}
// 检测是否平衡并恢复平衡
func (root *AVLNode) adjust() *AVLNode {
if root.Left.getHeight()-root.Right.getHeight() == 2 {
if root.Left.Left.getHeight() > root.Left.Right.getHeight() {
root = root.rightRotate() // 左偏 右旋
} else {
root = root.LR_Rotate()
}
} else if root.Left.getHeight()-root.Right.getHeight() == -2 {
if root.Right.Right.getHeight() > root.Right.Left.getHeight() {
root = root.leftRotate()
} else {
root = root.RL_Rotate()
}
}
return root
}
// 插入元素
func (root *AVLNode) insert(targer int) *AVLNode {
if root == nil { // 找到该插入的位置
return &AVLNode{
Val: targer,
}
}
if root.Val > targer {
root.Left = root.Left.insert(targer)
} else if root.Val < targer {
root.Right = root.Right.insert(targer)
} else {
fmt.Println("值已存在")
}
// 从插入节点开始 会有个回溯的过程
return root.adjust()
}
4、删除操作
删除操作步骤:
- 找到需要被删除的元素
- 有三种情况
叶子节点:直接删除 被删除的节点,只有左/右节点:父节点直接指向该节点的孩子节点 被删除节点左右孩子都在:找孩子树的最小节点 检查并恢复平衡性
涉及函数:删除、获取树高、LL/RR/LR/RL、获取右子树最小节点/左子树最大节点顶替
// 获取当前节点最左边的孩子
func getMinNode(root *AVLNode) *AVLNode {
for root.Left != nil {
root = root.Left
}
return root
}
// 删除元素
func (root *AVLNode) delete(targer int) *AVLNode {
if root == nil {
return nil
}
if root.Val == targer {
if root.Left == nil && root.Right == nil {
return nil
} else if root.Left == nil && root.Right != nil {
root = root.Right
} else if root.Left != nil && root.Right == nil {
root = root.Left
} else {
minNode := getMinNode(root.Right)
root.Val = minNode.Val
root.Right = root.Right.delete(minNode.Val)
}
} else if root.Val > targer {
root.Left = root.Left.delete(targer)
} else {
root.Right = root.Right.delete(targer)
}
return root.adjust()
}
↓↓↓↓↓↓↓************** 整体代码逻辑 **************↓↓↓↓↓↓↓
package main
import "fmt"
// 平衡二叉树的实现 (增删查)
type AVLNode struct {
Val int
Height int
Left *AVLNode
Right *AVLNode
}
// 查找元素
func (root *AVLNode) search(targer int) bool {
if root == nil {
return false
}
if root.Val > targer {
return root.Left.search(targer)
} else if root.Val < targer {
return root.Right.search(targer)
} else {
return true
}
}
// 两者取最大
func max(a, b int) int {
if a > b {
return a
}
return b
}
// 获取当前节点的高度
func (root *AVLNode) getHeight() int {
if root == nil {
return 0
}
return max(root.Left.getHeight(), root.Right.getHeight()) + 1
}
// 左旋转 RR
func (root *AVLNode) leftRotate() *AVLNode {
tmp := root.Right
root.Right = tmp.Left
tmp.Left = root
root = tmp
root.Height = root.getHeight()
return root
}
// 右旋 LL
func (root *AVLNode) rightRotate() *AVLNode {
tmp := root.Left
root.Left = tmp.Right
tmp.Right = root
root = tmp
root.Height = root.getHeight()
return root
}
// 先左旋后右旋
func (root *AVLNode) LR_Rotate() *AVLNode {
root.Left = root.Left.leftRotate() // 左孩子先旋转 变为LL模式,再右旋转
return root.rightRotate()
}
// 先右旋后左旋
func (root *AVLNode) RL_Rotate() *AVLNode {
root.Right = root.Right.rightRotate()
return root.leftRotate()
}
// 检测是否平衡并恢复平衡
func (root *AVLNode) adjust() *AVLNode {
if root.Left.getHeight()-root.Right.getHeight() == 2 {
if root.Left.Left.getHeight() > root.Left.Right.getHeight() {
root = root.rightRotate() // 左偏 右旋
} else {
root = root.LR_Rotate()
}
} else if root.Left.getHeight()-root.Right.getHeight() == -2 {
if root.Right.Right.getHeight() > root.Right.Left.getHeight() {
root = root.leftRotate()
} else {
root = root.RL_Rotate()
}
}
return root
}
// 插入元素
func (root *AVLNode) insert(targer int) *AVLNode {
if root == nil { // 找到该插入的位置
return &AVLNode{
Val: targer,
}
}
if root.Val > targer {
root.Left = root.Left.insert(targer)
} else if root.Val < targer {
root.Right = root.Right.insert(targer)
} else {
fmt.Println("值已存在")
}
// 从插入节点开始 会有个回溯的过程
return root.adjust()
}
// 获取当前节点最左边的孩子
func getMinNode(root *AVLNode) *AVLNode {
for root.Left != nil {
root = root.Left
}
return root
}
// 删除元素
func (root *AVLNode) delete(targer int) *AVLNode {
if root == nil {
return nil
}
if root.Val == targer {
if root.Left == nil && root.Right == nil {
return nil
} else if root.Left == nil && root.Right != nil {
root = root.Right
} else if root.Left != nil && root.Right == nil {
root = root.Left
} else {
minNode := getMinNode(root.Right)
root.Val = minNode.Val
root.Right = root.Right.delete(minNode.Val)
}
} else if root.Val > targer {
root.Left = root.Left.delete(targer)
} else {
root.Right = root.Right.delete(targer)
}
return root.adjust()
}
// 中序遍历,二叉搜索树的顺序性
// 之所以递归调用插入值,是因为后面有一个回溯判断节点是否平衡的过程
func (root *AVLNode) traversal() { // 中序遍历
if root == nil {
return
}
// 先打印左子树
root.Left.traversal()
// 再打印根节点
if root.Left != nil && root.Right != nil {
fmt.Printf("root=%v\t root.left=%v\t root.right=%v\n", root.Val, root.Left.Val, root.Right.Val)
} else if root.Left != nil && root.Right == nil {
fmt.Printf("root=%v\t root.left=%v\t root.right=nil\n", root.Val, root.Left.Val)
} else if root.Left == nil && root.Right != nil {
fmt.Printf("root=%v\t root.left=nil\t root.right=%v\n", root.Val, root.Right.Val)
} else {
fmt.Printf("root=%v\t root.left=nil\t root.right=nil\n", root.Val)
}
// 再打印右子树
root.Right.traversal()
}
// 测试数据
var append_list = []int{2, 3, 5, 6, 10, 17, 4}
var remove_list = []int{5, 1}
func main() {
treeNode := &AVLNode{
Left: nil,
Right: nil,
Height: 0,
Val: 1,
}
// 循环添加元素
for i := 0; i < len(append_list); i++ {
treeNode = treeNode.insert(append_list[i])
}
treeNode.traversal()
fmt.Println()
//循环删除元素
for i := 0; i < len(remove_list); i++ {
treeNode = treeNode.delete(remove_list[i])
}
treeNode.traversal()
}
输出结果
root=1 root.left=nil root.right=nil
root=2 root.left=1 root.right=3
root=3 root.left=nil root.right=4
root=4 root.left=nil root.right=nil
root=5 root.left=2 root.right=10
root=6 root.left=nil root.right=nil
root=10 root.left=6 root.right=17
root=17 root.left=nil root.right=nil------------------------------------------------------
root=2 root.left=nil root.right=nil
root=3 root.left=2 root.right=4
root=4 root.left=nil root.right=nil
root=6 root.left=3 root.right=10
root=10 root.left=nil root.right=17
root=17 root.left=nil root.right=nil