做一个代码世界的设计师!🍺|

Jikefan

园龄:4年11个月粉丝:5关注:4

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,

本文作者:jikefan

本文链接:https://www.cnblogs.com/jikefan/articles/18574105

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Jikefan  阅读(10)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.

作曲 : Reol

作词 : Reol

fade away...do over again...

fade away...do over again...

歌い始めの一文字目 いつも迷ってる

歌い始めの一文字目 いつも迷ってる

どうせとりとめのないことだけど

伝わらなきゃもっと意味がない

どうしたってこんなに複雑なのに

どうしたってこんなに複雑なのに

噛み砕いてやらなきゃ伝わらない

ほら結局歌詞なんかどうだっていい

僕の音楽なんかこの世になくたっていいんだよ

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

僕は気にしない 君は気付かない

何処にももういないいない

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

忘れていく 忘れられていく

We don't know,We don't know.

目の前 広がる現実世界がまた歪んだ

目の前 広がる現実世界がまた歪んだ

何度リセットしても

僕は僕以外の誰かには生まれ変われない

「そんなの知ってるよ」

気になるあの子の噂話も

シニカル標的は次の速報

麻痺しちゃってるこっからエスケープ

麻痺しちゃってるこっからエスケープ

遠く遠くまで行けるよ

安定なんてない 不安定な世界

安定なんてない 不安定な世界

安定なんてない きっと明日には忘れるよ

fade away...do over again...

fade away...do over again...

そうだ世界はどこかがいつも嘘くさい

そうだ世界はどこかがいつも嘘くさい

綺麗事だけじゃ大事な人たちすら守れない

くだらない 僕らみんなどこか狂ってるみたい

本当のことなんか全部神様も知らない

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

僕は気にしない 君は気付かない

何処にももういないいない

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

忘れていく 忘れられていく

We don't know,We don't know.