AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树。查找、插入和删除在平均和最坏情况下都是O(log n)。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。AVL树得名于它的发明者G.M. Adelson-Velsky和E.M. Landis,他们在1962年的论文《An algorithm for the organization of information》中发表了它。
节点的平衡因子是它的左子树的高度减去它的右子树的高度(有时相反)。带有平衡因子1、0或 -1的节点被认为是平衡的。带有平衡因子 -2或2的节点被认为是不平衡的,并需要重新平衡这个树。平衡因子可以直接存储在每个节点中,或从可能存储在节点中的子树高度计算出来。
AVL数在插入或删除节点之后很可能对不再平衡,这时,需要进行几次所谓的“AVL”旋转。以下图表以四列表示四种情况,每行表示在该种情况下要进行的操作。在左左和右右的情况下,只需要进行一次旋转操作;在左右和右左的情况下,需要进行两次旋转操作。
插入
向AVL树插入可以通过如同它是未平衡的二叉查找树一样把给定的值插入树中,接着自底向上向根节点折回,于在插入期间成为不平衡的所有节点上进行旋转来完成。因为折回到根节点的路途上最多有1.44乘log n个节点,而每次AVL旋转都耗费恒定的时间,插入处理在整体上耗费O(log n) 时间。
删除
从AVL树中删除可以通过把要删除的节点向下旋转成一个叶子节点,接着直接剪除这个叶子节点来完成。因为在旋转成叶子节点期间最多有log n个节点被旋转,而每次AVL旋转耗费恒定的时间,删除处理在整体上耗费O(log n) 时间。
以上均引自维基百科:http://zh.wikipedia.org/wiki/AVL%E6%A0%91
插入思路:
向AVL树插入是个查找寻位的过程,right 或 left,比较容易实现。但插入之后,寻路路过的节点的平衡因子可能会改变,从而导致树不再平衡,这时候就需对不平衡的节点进行旋转。
问题是怎么确定不平衡的节点,即不平衡的树是的root节点在哪里?
已知在平衡因子为0的节点的子树任一位置插入一个节点,该节点的平衡因子变换只是在-1,0,1之间,由此可得,不平衡树的root节点平衡因子不为0.从root节点开始,寻位路过的节点的平衡因子均会改变。
旋转要做的就是把root子树整平衡。此需要知道几个元素:
1. 指向不平衡树root节点,指向root节点的parent(可由变量 r、p保存,寻位时,出现平衡因子不为0的节点更新)
2. 插入节点后,从root开始,各节点的平衡因子(可有数组保存每次寻位是left还是right,然后平衡因子相应加减1)
更新平衡因子之后,判断root的平衡因子,若不为正负2,直接返回,若是,就根据上图四中情况进行旋转。
注意点:左右、右左情况旋转后平衡因子的更新。
删除思路:
从AVL树中删除可以通过把要删除的节点向下旋转成一个叶子节点,接着直接剪除这个叶子节点来完成。然后根据寻路
路径,由下向上进行如下步骤:
1. 更新平衡因子
2. 判断,是否影响Parent的平衡因子,未影响则退出。
3. 旋转,再进行步骤 2,若还有影响,则进行步骤4
4. 对Parent进行步骤 1(奈何不知道在哪里画流程图^_^)
另一种表达方式:
删除的节点向下旋转成一个叶子节点即为一个叶子节点和待删除节点交换位置。
定义:待删除节点del_node, 待交换的叶子节点swap_node
可以推测swap_node需为del_node左子树的最大值或右子树的最大值。
以交换del_node的右子树为例:
1. 查找del_node,保存查找路径节点及方向分别存储在pnode[k],dir[k];
2. del_node若无left child,则直接删除;若有,判断right child的左孩子节点是否为NULL,若为NULL,也可直接
删除,若不为NULL,就查找右子树的最小值swap_node,进行替换。
3. 从k开始,更新pnode[k]节点的平衡因子,根据dir[k],进行加减。(平衡因子 = 左子树高度 - 右子树高度; dir=0,表示左转,1表示右转)
因为查询方向会影响pnode[k]的平衡因子,所以可以现根据dir的方向判断:
dir[k] = 0(向left方向)查找:
则对pnode[k]的平衡因子减1更新:
1. 若更新后为-1,则之前pnode[k]平衡因子为0,此时它的平衡因子的改变并不会影响到它parent节点的平衡因子,所以可直接退出。
2. 若更新后为0,则之前pnode[k]的平衡因子为1,此时更新后,pnode[k]的高度降低,所以可能会影响它的parent的平衡因子,所以要对它的parent即
pnode[k-1]进行更新平衡因子和类似判断操作。
3. 若更新后为-2,则之前pnode[k]的平衡因子为-1,此时更新后,pnode[k]子树不平衡,要先对其旋转,然后判断高度是否改变。此时的关键就取决于p[k]的
右子树的平衡因子rc。
若rc = 0: 则旋转后,高度不会变,可直接退出。
若rc = 1:就是上图右左情况,可进行右旋左旋,使其平衡,此时高度将1,对pnode[k-1]进行平衡因子更新判断。
若rc = -1:就是上图右右情况,可进行左旋,使其平衡,此时高度将1,对pnode[k-1]进行平衡因子更新判断。
当dir[k] = 1时,步骤类似,不再赘述。
太懒了,,嗨嗨!AVL难点在于delete删除,想了好长时间,总算找到关键点:删除叶子节点会不会影响parent的高度,进而影响更上层的平衡因子。
以后要多想点,写点东西了,水平较次,欢迎指点.
嗨嗨, 也来个转载请注明出处:http://www.cnblogs.com/chagmf/p/3878697.html