https://github.com/xieqing/avl-tree

An AVL Tree Implementation In C

There are several choices when implementing AVL trees:

  • store height or balance factor
  • store parent reference or not
  • recursive or non-recursive (iterative)

This implementation's choice:

  • store balance factor
  • store parent reference
  • non-recursive (iterative)

Files:

  • avl_bf.h - AVL tree header
  • avl_bf.c - AVL tree library
  • avl_data.h - data header
  • avl_data.c - data library
  • avl_example.c - example code for AVL tree application
  • avl_test.c - unit test program
  • avl_test.sh - unit test shell script
  • README.md - implementation note

If you have suggestions, corrections, or comments, please get in touch with xieqing.

DEFINITION

The AVL tree is named after its two Soviet inventors, Georgy Adelson-Velsky and Evgenii Landis, who published it in their 1962 paper "An algorithm for the organization of information". It was the first such data structure to be invented.

In an AVL tree, the heights of the two child subtrees of any node differ by at most one; each node stores its height (alternatively, can just store difference in heights), if at any time they differ by more than one, rebalancing is done to restore this property.

In a binary search tree the balance factor of a node N is defined to be the height difference of its two child subtrees.

  1. BalanceFactor(N) = Height(RightSubtree(N)) Height(LeftSubtree(N))

A binary search tree is defined to be an AVL tree if the invariant holds for every node N in the tree.

  1. BalanceFactor(N) {–1,0,+1}

A node N with BalanceFactor(N) < 0 is called "left-heavy", one with BalanceFactor(N) > 0 is called "right-heavy", and one with BalanceFactor(N) = 0 is sometimes simply called "balanced".

Balance factors can be kept up-to-date by knowning the previous balance factors and the change in height - it is not necesary to know the absolute height.

Two main properties of AVL trees:

  • Binary Search Property: in-order sequence of the keys, ensures that we can search for any value in O(height);
  • Balance Factor Property: the heights of two child subtrees of any node differ by at most one, ensures that the height of an AVL tree is always O(log N).

ROTATION

It is easy to check that a single rotation preserves the ordering requirement for a binary search tree. The keys in subtree A are less than or equal to x, the keys in tree C are greater than or equal to y, and the keys in B are between x and y.

  1. Before rotation
  2. x
  3. / \
  4. A y
  5. / \
  6. B C
  7. After rotation
  8. y
  9. / \
  10. x C
  11. / \
  12. A B

SEARCH

Searching for a specific key in an AVL tree can be done the same way as that of a normal binary search tree.

MODIFICATION

After a modifying operation (e.g. insertion, deletion) it is necessary to update the balance factors of all nodes, a little thought should convince you that all nodes requiring correction must be on the path from the root to the modified node, and these nodes are ancestors of the modified node.

If a temporary height difference of more than one arises between two child subtrees, the parent subtree has to be rebalanced by rotations.

Rotations never violate the binary search property and the balance factor property, insertions and deletions never violate the binary search property, and violations of the balance factor property can be restored by rotations.

INSERTION

The effective insertion of the new node increases the height of the corresponding child tree from 0 to 1. Starting at this subtree, it is necessary to check each of the ancestors for consistency with the invariants of AVL trees.

  1. insert as in simple binary search tree.
  2. backtrack the top-down path from the root to the new node: update the balance factor of parent node; rebalance if the balance factor of parent node temporarily becomes +2 or -2 (parent subtree has the same height as before, thus backtracking terminate immediately); terminate if the height of that parent subtree remains unchanged (has the same height as before insertion).

Inserting

  1. Replace the termination NIL pointer with the new node
  2. Before insertion
  3. parent
  4. |
  5. NIL (current)
  6. After insertion
  7. parent (height increased)
  8. |
  9. new_node (current)
  10. / \
  11. NIL NIL

Rebalancing

  1. Let x be the lowest node that violates the AVL property and let h be the height of its shorter subtree.
  2. The first case: insert under x.left
  3. 1. insert under x.left.left
  4. Before insertion
  5. x (h+2)
  6. / \
  7. (h+1) y C (h)
  8. / \
  9. (h) A B (h)
  10. ^ insert (A may be NIL)
  11. bf(y) = 0; bf(x) = -1; height = h+2
  12. After insertion (y's balance factor has been updated)
  13. x (h+3)
  14. / \
  15. (h+2) y C (h)
  16. / \
  17. (h+1) A B (h)
  18. bf(y) = -1; bf(x) = -1; height = h+2
  19. After right rotation
  20. y (h+2)
  21. / \
  22. (h+1) A x (h+1)
  23. / \
  24. (h) B C (h)
  25. bf(x) = 0; bf(y) = 0; height = h+2 (height unchanged)
  26. 2. insert under x.left.right
  27. Before insertion
  28. x (h+2)
  29. / \
  30. (h+1) y C (h)
  31. / \
  32. (h) A B (h)
  33. ^ insert (B may be NIL)
  34. bf(y) = 0; bf(x) = -1; height = h+2
  35. After insertion (y's balance factor has been updated)
  36. x (h+3)
  37. / \
  38. (h+2) y C (h)
  39. / \
  40. (h) A B (h+1)
  41. bf(y) = 1; bf(x) = -1; height = h+2
  42. Let's expand B one more level (since B has height h+1, it cannot be empty)
  43. x (h+3)
  44. / \
  45. (h+2) y C (h)
  46. / \
  47. (h) A z' (h+1)
  48. / \
  49. (h/h-1/h=0) U V (h-1/h/h=0)
  50. After left rotation
  51. x
  52. / \
  53. z C
  54. / \
  55. y V
  56. / \
  57. A U
  58. After right rotation
  59. z (h+2)
  60. / \
  61. / \
  62. (h+1) y x (h+1)
  63. / \ / \
  64. (h) A U V C (h)
  65. (h/h-1/h=0)(h-1/h/h=0)
  66. bf(z') = -1; bf(y) = 0; bf(x) = 1; bf(z) = 0; height = h+2 (height unchanged)
  67. bf(z') = 1; bf(y) = -1; bf(x) = 0; bf(z) = 0; height = h+2 (height unchanged)
  68. bf(z') = 0; bf(y) = 0; bf(x) = 0; bf(z) = 0; height = h+2 (height unchanged)
  69. The second case: insert under x.right
  70. 1. insert under x.right.right
  71. Before insertion
  72. x (h+2)
  73. / \
  74. (h) A y (h+1)
  75. / \
  76. (h) B C (h)
  77. ^ insert (C may be NIL)
  78. bf(y) = 0; bf(x) = 1; height = h+2
  79. After insertion (y's balance factor has been updated)
  80. x
  81. / \
  82. (h) A y (h+2)
  83. / \
  84. (h) B C (h+1)
  85. bf(y) = 1; bf(x) = 1; height = h+2
  86. After left rotation
  87. y (h+2)
  88. / \
  89. (h+1) x C (h+1)
  90. / \
  91. (h) A B (h)
  92. bf(x) = 0; bf(y) = 0; height = h+2 (height unchanged)
  93. 2. insert under x.right.left
  94. Before insertion
  95. x (h+2)
  96. / \
  97. (h) A y (h+1)
  98. / \
  99. (h) B C (h)
  100. ^ insert (B may be NIL)
  101. bf(y) = 0; bf(x) = 1; height = h+2
  102. After insertion (y's balance factor has been updated)
  103. x
  104. / \
  105. (h) A y (h+2)
  106. / \
  107. (h+1) B C (h)
  108. bf(y) = -1; bf(x) = 1; height = h+2
  109. Let's expand it one more level (since B has height h+1, it cannot be empty)
  110. x (h+3)
  111. / \
  112. (h) A y (h+2)
  113. / \
  114. (h+1) z' C (h)
  115. / \
  116. (h/h-1/h=0) U V (h-1/h/h=0)
  117. After right rotation
  118. x
  119. / \
  120. A z
  121. / \
  122. U y
  123. / \
  124. V C
  125. After left rotation
  126. z (h+2)
  127. / \
  128. / \
  129. (h+1) y x (h+1)
  130. / \ / \
  131. (h) A U V C (h)
  132. (h/h-1/h=0)(h-1/h/h=0)
  133. bf(z') = -1; bf(y) = 0; bf(x) = 1; bf(z) = 0; height = h+2 (height unchanged)
  134. bf(z') = 1; bf(y) = -1; bf(x) = 0; bf(z) = 0; height = h+2 (height unchanged)
  135. bf(z') = 0; bf(y) = 0; bf(x) = 0; bf(z) = 0; height = h+2 (height unchanged)

DELETION

The effective deletion of the subject node or the replacement node decreases the height of the corresponding child tree either from 1 to 0 or from 2 to 1, if that node had a child. Starting at this subtree, it is necessary to check each of the ancestors for consistency with the invariants of AVL trees.

  1. find the subject node or its replacement node (in-order successor) if the subject node has two children, not to remove it for the time being.
  2. backtrack the top-down path from the root to the subject node or the replacement node: update the balance factor of parent node; rebalance if the balance factor of parent node temporarily becomes +2 or -2; terminate if the height of that parent subtree remains unchanged (has the same height as before deletion).
  3. remove the subject node or the replacement node.

Rebalancing

  1. Let x be the lowest node that violates the AVL property and let h+1 be the height of its shorter subtree.
  2. The first case: delete under x.right
  3. 1. x.left is left-heavy or balanced
  4. Before deletion
  5. x (h+3)
  6. / \
  7. (h+2) y C (h+1)
  8. / \ ^ delete
  9. (h+1/h+1) A B (h/h+1)
  10. bf(y) = -1; bf(x) = -1; height = h+3
  11. bf(y) = 0; bf(x) = -1; height = h+3
  12. After deletion
  13. x
  14. / \
  15. (h+2) y' C (h)
  16. / \
  17. (h+1/h+1) A B (h/h+1)
  18. After right rotation
  19. y (h+2/h+3)
  20. / \
  21. (h+1/h+1) A x (h+1/h+2)
  22. / \
  23. (h/h+1) B C (h)
  24. bf(y') = -1; bf(x) = 0; bf(y) = 0; height = h+2 (height decreased)
  25. bf(y') = 0; bf(x) = -1; bf(y) = 1; height = h+3 (height unchanged)
  26. 2. x.left is right-heavy
  27. Before deletion
  28. x (h+3)
  29. / \
  30. (h+2) y C (h+1)
  31. / \ ^ delete
  32. (h) A B (h+1)
  33. bf(y) = 1; bf(x) = -1; height = h+3
  34. After deletion
  35. x (h+1)
  36. / \
  37. (h+2) y C (h)
  38. / \
  39. (h) A B (h+1)
  40. Let's expand B one more level (since B has height h+1, it cannot be empty)
  41. (h+3) x
  42. / \
  43. (h+2) y C (h)
  44. / \
  45. (h) A z' (h+1)
  46. / \
  47. (h/h-1/h) U V (h-1/h/h)
  48. After left rotation
  49. x
  50. / \
  51. z C
  52. / \
  53. y V
  54. / \
  55. A U
  56. After right rotation
  57. z (h+2)
  58. / \
  59. / \
  60. (h+1) y x (h+1)
  61. / \ / \
  62. (h) A U V C (h)
  63. (h/h-1/h)(h-1/h/h)
  64. bf(z') = -1; bf(y) = 0; bf(x) = 1; bf(z) = 0; height = h+2 (height decreased)
  65. bf(z') = 1; bf(y) = -1; bf(x) = 0; bf(z) = 0; height = h+2 (height decreased)
  66. bf(z') = 0; bf(y) = 0; bf(x) = 0; bf(z) = 0; height = h+2 (height decreased)
  67. The sencond case: delete under x.left
  68. 1. x.right is right-heavy or balanced
  69. Before deletion
  70. x (h+3)
  71. / \
  72. (h+1) A y (h+2)
  73. delete ^ / \
  74. (h/h+1) B C (h+1/h+1)
  75. bf(y) = 1; bf(x) = 1; height = h+3
  76. bf(y) = 0; bf(x) = 1; height = h+3
  77. After deletion
  78. x (h+3)
  79. / \
  80. (h) A y' (h+2)
  81. / \
  82. (h/h+1) B C (h+1/h+1)
  83. After left rotation
  84. y (h+2/h+3)
  85. / \
  86. (h+1/h+2) x C (h+1/h+1)
  87. / \
  88. (h) A B (h/h+1)
  89. bf(y') = 1; bf(x) = 0; bf(y) = 0; height = h+2 (height decreased)
  90. bf(y') = 0; bf(x) = 1; bf(y) = -1; height = h+3 (height unchanged)
  91. 2. x.right is left-heavy
  92. Before deletion
  93. x (h+3)
  94. / \
  95. (h+1) A y (h+2)
  96. delete ^ / \
  97. (h+1) B C (h)
  98. bf(y) = -1; bf(x) = 1; height = h+3
  99. After deletion
  100. x (h+3)
  101. / \
  102. (h) A y (h+2)
  103. / \
  104. (h+1) B C (h)
  105. Let's expand B one more level (since B has height h+1, it cannot be empty)
  106. x (h+3)
  107. / \
  108. (h) A y (h+2)
  109. / \
  110. (h+1) z' C (h)
  111. / \
  112. (h/h-1/h) U V (h-1/h/h)
  113. After right rotation
  114. x
  115. / \
  116. A z
  117. / \
  118. U y
  119. / \
  120. V C
  121. After left rotation
  122. z (h+2)
  123. / \
  124. / \
  125. (h+1) y x (h+1)
  126. / \ / \
  127. (h) A U V C (h)
  128. (h/h-1/h)(h-1/h/h)
  129. bf(z') = -1; bf(y) = 0; bf(x) = 1; bf(z) = 0; height = h+2 (height decreased)
  130. bf(z') = 1; bf(y) = -1; bf(x) = 0; bf(z) = 0; height = h+2 (height decreased)
  131. bf(z') = 0; bf(y) = 0; bf(x) = 0; bf(z) = 0; height = h+2 (height decreased)

Removing

  1. Replace the subject node or the replacement node with its child (which may be NIL)
  2. parent
  3. | parent
  4. node -> |
  5. / \ child/NIL
  6. child/NIL/NIL NIL/child/NIL

References

  1. https://en.wikipedia.org/wiki/AVL_tree
  2. https://www.cs.usfca.edu/~galles/visualization/AVLtree.html

License

Copyright (c) 2019 xieqing. https://github.com/xieqing

May be freely redistributed, but copyright notice must be retained.

AVL树实现记录的更多相关文章

  1. 算法与数据结构(十一) 平衡二叉树(AVL树)

    今天的博客是在上一篇博客的基础上进行的延伸.上一篇博客我们主要聊了二叉排序树,详情请戳<二叉排序树的查找.插入与删除>.本篇博客我们就在二叉排序树的基础上来聊聊平衡二叉树,也叫AVL树,A ...

  2. AVL树

    AVL树 在二叉查找树(BST)中,频繁的插入操作可能会让树的性能发生退化,因此,需要加入一些平衡操作,使树的高度达到理想的O(logn),这就是AVL树出现的背景.注意,AVL树的起名来源于两个发明 ...

  3. PAT树_层序遍历叶节点、中序建树后序输出、AVL树的根、二叉树路径存在性判定、奇妙的完全二叉搜索树、最小堆路径、文件路由

    03-树1. List Leaves (25) Given a tree, you are supposed to list all the leaves in the order of top do ...

  4. AVL树插入操作实现

    为了提高二插排序树的性能,规定树中的每个节点的左子树和右子树高度差的绝对值不能大于1.为了满足上面的要求需要在插入完成后对树进行调整.下面介绍各个调整方式. 右单旋转 如下图所示,节点A的平衡因子(左 ...

  5. 数据结构——二叉查找树、AVL树

    二叉查找树:由于二叉查找树建树的过程即为插入的过程,所以其中序遍历一定为升序排列! 插入:直接插入,插入后一定为根节点 查找:直接查找 删除:叶子节点直接删除,有一个孩子的节点删除后将孩子节点接入到父 ...

  6. 平衡二叉树,AVL树之图解篇

    学习过了二叉查找树,想必大家有遇到一个问题.例如,将一个数组{1,2,3,4}依次插入树的时候,形成了图1的情况.有建立树与没建立树对于数据的增删查改已经没有了任何帮助,反而增添了维护的成本.而只有建 ...

  7. My集合框架第三弹 AVL树

    旋转操作: 由于任意一个结点最多只有两个儿子,所以当高度不平衡时,只可能是以下四种情况造成的: 1. 对该结点的左儿子的左子树进行了一次插入. 2. 对该结点的左儿子的右子树进行了一次插入. 3. 对 ...

  8. 红黑树和AVL树的实现与比较-----算法导论

    一.问题描述 实现3种树中的两种:红黑树,AVL树,Treap树 二.算法原理 (1)红黑树 红黑树是一种二叉查找树,但在每个结点上增加一个存储位表示结点的颜色,可以是red或black.红黑树满足以 ...

  9. AVL树的插入删除查找算法实现和分析-1

    至于什么是AVL树和AVL树的一些概念问题在这里就不多说了,下面是我写的代码,里面的注释非常详细地说明了实现的思想和方法. 因为在操作时真正需要的是子树高度的差,所以这里采用-1,0,1来表示左子树和 ...

随机推荐

  1. Java Socket NIO

    服务端: public class NIOServer { private static final String HOST = "localhost"; private stat ...

  2. 13行代码实现:Python实时视频采集(附源码)

    一.前言 本文是<人脸识别完整项目实战>系列博文第3部分:程序设计篇(Python版),第1节<Python实时视频采集程序设计>,本章内容系统介绍:基于Python+open ...

  3. MYSQL登录函数(第3版本)

    已经改进 CREATE DEFINER=`root`@`%` FUNCTION `uc_session_login`( `reqjson` JSON, `srvjson` JSON ) RETURNS ...

  4. Java核心-多线程-并发控制器-Semaphore信号量

    Semaphore是非常有用的一个多线程并发控制组件(Java还有CountDownLatch.CyclicBarrier.Exchanger多线程组件),它相当于是一个并发控制器,是用于管理信号量的 ...

  5. OSPFV3综合实验 (第三组)

    拓扑图 本次试验规划:拓扑分4个区域,其中区域2采用帧中继实现区域内互通的前提下配置OSPF.ospfv3.R7与R8之间配置rip实现互通,区域1作为nssa区域,实现路由注入.最终实现全局互通. ...

  6. [UE4]重构Grab和Drop

    一.在前面的实例中是把Grab和Drop逻辑放到SimVRHand手柄对象里面,从面向对象来看,Grab和Drop逻辑应该放在被抓取的对象中,因为可能每个对象被抓取后要执行的Grab和Drop逻辑都不 ...

  7. C#使用AppDomain时的异常分析:Object ‘XXXX.rem’ has been disconnected or does not exist at the server.

    在使用C#的应用程序域的时候,碰到这么一个异常: System.Runtime.Remoting.RemotingException: Object ‘/76e7cd41_2cd2_4e89_9c03 ...

  8. 给datagridview的下拉框添加valueChange事件

    修改datagridview的EditMode属性为EdutOnEnter,否则需要点2次以上才出现下拉框 1.给DataGridView添加EditingControlShowing事件: 2.编辑 ...

  9. java基础回忆、复习(一)

    一:浅拷贝与深拷贝: 对于基本数据类型,直接进行拷贝,String类型,有两种拷贝方式: 1:直接将原对象中的name的引用值拷贝给新对象的name字段.<浅拷贝> 2:根据原对象中的na ...

  10. js原生倒计时

    倒计时是2019年6月7号10点开始的 代码粘贴过去直接运行即可 <!DOCTYPE html> <html lang="en"> <head> ...