• 左旋和右旋示意图
  • 四种情况及解决方案
  • AVL 的逻辑分析
  • AVL in Go

旋转

左旋

image.png

右旋

image.png

四种情况

左左

image.png

右右

image.png

左右

image.png

右左

image.png

逻辑分析

记录当前节点的状态 Abs(state) <= 1 ,每次发生一点不平衡就会修正,分为以上四种情况。

AVL in Golang

这段代码来自:gods

  1. // Tree holds elements of the AVL tree.
  2. type Tree struct {
  3. Root *Node // Root node
  4. Comparator utils.Comparator // Key comparator
  5. size int // Total number of keys in the tree
  6. }
  7. // Node is a single element within the tree
  8. type Node struct {
  9. Key interface{}
  10. Value interface{}
  11. Parent *Node // Parent node
  12. Children [2]*Node // Children nodes
  13. b int8
  14. }

其中 b 是用来表明节点是否平衡的,children[0] 代表左节点,children[1] 代表右节点。后面通过亦或运算来统一左旋和右旋,很优秀。

  1. func singlerot(c int8, s *Node) *Node {
  2. s.b = 0
  3. s = rotate(c, s)
  4. s.b = 0
  5. return s
  6. }
  7. func doublerot(c int8, s *Node) *Node {
  8. a := (c + 1) / 2
  9. r := s.Children[a]
  10. s.Children[a] = rotate(-c, s.Children[a])
  11. p := rotate(c, s)
  12. switch {
  13. default:
  14. s.b = 0
  15. r.b = 0
  16. case p.b == c:
  17. s.b = -c
  18. r.b = 0
  19. case p.b == -c:
  20. s.b = 0
  21. r.b = c
  22. }
  23. p.b = 0
  24. return p
  25. }
  26. // c < 0 时为右旋,c > 0 时为左旋
  27. func rotate(c int8, s *Node) *Node {
  28. a := (c + 1) / 2
  29. r := s.Children[a]
  30. s.Children[a] = r.Children[a^1]
  31. if s.Children[a] != nil {
  32. s.Children[a].Parent = s
  33. }
  34. r.Children[a^1] = s
  35. r.Parent = s.Parent
  36. s.Parent = r
  37. return r
  38. }

数学基础:AVL - 图7

通过亦或,将左旋和右旋统一在一起,singlerot 统一了左左和右右的情况,doublerot 统一的左右和右左的情况。

整个流程通过参数 c 来控制左旋还是右旋,由 c 可以获取左节点还是有节点,节点位置 a = (c + 1) / 2

avl-put.svg

这里面只列出了部分关键代码,完整代码青岛 Github 上自行查看