树--平衡二叉树(AVL)

平衡二叉树

  1. 概念
  2. 查找
  3. 插入
  4. 删除

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、插入操作

插入操作步骤:

  1. 找到对应位置插入 
  2. 根据 树高 判断是否 平衡 
  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、删除操作

删除操作步骤:

  1. 找到需要被删除的元素
  2. 有三种情况
    叶子节点:直接删除
    被删除的节点,只有左/右节点:父节点直接指向该节点的孩子节点
    被删除节点左右孩子都在:找孩子树的最小节点
  3. 检查并恢复平衡性

涉及函数:删除、获取树高、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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值