go实现平衡二叉树(构建、遍历)

AVL树(自平衡搜索二叉树)的应用场景和特点

AVL 树是一种自平衡二叉搜索树(Self-Balancing Binary Search Tree, SBBST),由 G.M. Adelson-Velsky 和 E.M. Landis 在 1962 年提出。AVL 树的特点是任何节点的两个子树的高度差最多为 1,这保证了树的高度保持在 O(log n),从而确保了查找、插入和删除操作的时间复杂度均为 O(log n)。

特点

  1. 自平衡

    • AVL 树通过旋转操作来保持平衡。当插入或删除一个节点导致树不平衡时,AVL 树会执行一系列的旋转操作(左旋、右旋、左右旋、右左旋)来恢复平衡。
  2. 高度平衡

    • 由于每个节点的左右子树高度差不超过 1,AVL 树的高度始终保持在 O(log n),这使得它的操作效率很高。
  3. 严格的平衡条件

    • 这种严格的平衡条件保证了所有基本操作(如查找、插入、删除)的最坏情况时间复杂度都是 O(log n)。
  4. 内存开销

    • 每个节点需要额外的空间来存储其高度信息,用于判断是否需要进行平衡操作。
  5. 插入和删除操作较复杂

    • 相比于普通二叉搜索树,AVL 树的插入和删除操作更复杂,因为需要维护平衡性,这涉及更多的计算和旋转操作。

应用场景

  1. 数据库索引

    • 在数据库系统中,AVL 树可以用来实现高效的索引结构,特别是在数据量较大且频繁进行查找操作的情况下。
  2. 实时系统

    • 对于需要快速响应查询的实时系统,AVL 树提供了一种可靠的数据结构选择。
  3. 符号表

    • 在编译器设计中,AVL 树可以用作符号表,以支持快速的变量查找和更新。
  4. 集合和映射

    • 在需要高效地管理有序集合或键值对的应用中,AVL 树是一个很好的选择。
  5. 内存中的数据结构

    • 当需要在内存中维护一个动态的有序集合,并且要求操作具有较高的性能时,AVL 树是一个合适的选择。

总结

AVL 树适合那些需要高效查找、插入和删除操作,并且对数据有序性的应用场景。它通过严格的平衡条件保证了操作的高效性,但同时也带来了更高的实现复杂度。对于需要在数据动态变化的同时保持高效率的应用来说,AVL 树是一个非常强大的工具。然而,在某些情况下,如果不需要如此严格的平衡条件,或者数据集较小,使用其他数据结构(如红黑树)可能更为合适,因为它们在实现上相对简单一些。

代码

package main

import "fmt"

type TreeNode struct {
	value  int
	height int
	left   *TreeNode
	right  *TreeNode
}

type AVLTree struct {
	root *TreeNode
}

func (n *TreeNode) Height() int {
	if n == nil {
		return 0
	}

	return n.height
}

func maxHeight(a *TreeNode, b *TreeNode) int {
	if a.Height() > b.Height() {
		return a.Height()
	}

	return b.Height()
}

func computedBalanceFactor(n *TreeNode) int {
	return n.left.Height() - n.right.Height()
}

func (tree *AVLTree) Insert(value int) {
	tree.root = tree.insert(tree.root, value)
}

func (tree *AVLTree) insert(node *TreeNode, value int) *TreeNode {
	if node == nil {
		return &TreeNode{value: value, height: 1}
	}

	if value < node.value {
		node.left = tree.insert(node.left, value)
	} else if value > node.value {
		node.right = tree.insert(node.right, value)
	} else {
		return node
	}

	node.height = 1 + maxHeight(node.left, node.right)

	balanceFactor := computedBalanceFactor(node)

	// 右右
	if balanceFactor < -1 && value > node.right.value {
		return tree.leftRotate(node)
	}
	// 左左
	if balanceFactor > 1 && value < node.left.value {
		return tree.rightRotate(node)
	}
	// 右左
	if balanceFactor < -1 && value < node.right.value {
		node.right = tree.rightRotate(node.right)
		return tree.leftRotate(node)
	}
	// 左右
	if balanceFactor > 1 && value > node.left.value {
		node.left = tree.leftRotate(node.left)
		return tree.rightRotate(node)
	}

	return node
}

func (tree *AVLTree) leftRotate(node *TreeNode) *TreeNode {
	y := node.right
	T2 := y.left
	y.left = node
	node.right = T2

	node.height = 1 + maxHeight(node.left, node.right)
	y.height = 1 + maxHeight(y.left, y.right)
	return y
}

func (tree *AVLTree) rightRotate(node *TreeNode) *TreeNode {
	x := node.left
	T2 := x.right
	x.right = node
	node.left = T2

	node.height = 1 + maxHeight(node.left, node.right)
	x.height = 1 + maxHeight(x.left, x.right)
	return x
}

func (tree *AVLTree) PrintTree() {
	tree.printTree(tree.root, 0)
	fmt.Println()
}

func (tree *AVLTree) printTree(node *TreeNode, level int) {
	if node != nil {
		tree.printTree(node.right, level+1)
		fmt.Println()
		for i := 0; i < level; i++ {
			fmt.Print("\t")
		}
		fmt.Print(node.value)
		tree.printTree(node.left, level+1)
	}
}

func (tree *AVLTree) PreOrder() {
	tree.preOrder(tree.root)
}

func (tree *AVLTree) preOrder(node *TreeNode) {
	if node == nil {
		return
	}

	if node.left != nil {
		tree.preOrder(node.left)
	}
	fmt.Print(node.value, ", ")
	if node.right != nil {
		tree.preOrder(node.right)
	}
}

func main() {
	tree := AVLTree{}

	values := []int{10, 30, 20, 40, 5, 25}

	for _, v := range values {
		tree.Insert(v)
	}

	tree.PrintTree()

	// 前序遍历出来的结果是顺序的,参考快速排序
	tree.PreOrder()
}

结果

		40
	30
		25
20
	10
		5
5, 10, 20, 25, 30, 40, 

posted @ 2024-11-28 13:26  Jikefan  阅读(58)  评论(0)    收藏  举报