AVL树

 AVL树是一个平衡二叉搜索树。AVL树的 高度 的两个 孩子 节点的子树最多相差一个,如果在任何时候他们相差不止一个,再平衡完成恢复这个属性。

节点的平衡因子是它的右子树的高度减去它的左子树的高度。带有平衡因子 1、0 或 -1 的节点被认为是平衡的。带有平衡因子 -2 或 2 的节点被认为是不平衡的,并需要重新平衡这个树。平衡因子可以直接存储在每个节点中,或从可能存储在节点中的子树高度计算出来。


我们再来看看它的效率:


以上,我们便了解了AVL树,那么我们就知道,如果要保持平衡因子的的平衡,从而使整个树保持平衡,是不容易的,那么怎样才能保持平衡呢?

在维基百科中是这样说的,它叫这种插入叫做追溯循环的插入。

我们首先不要关注它为什么叫这个名字,我们先看看它有几种情况


以上便是第一种情况:

<span style="font-size:18px;">void _RotateL(Node* &parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		parent->_right = subRL;

		if(subRL)
			subRL->_parent = parent;
		subR->_left = parent;
		subR->_parent = parent->_parent;
		parent->_parent = subR;

		parent = subR;
		parent->bf = 0;
	}</span>



<span style="font-size:18px;">void _RotateR(Node* &parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		parent->_left = subLR;
		if(subLR)
			subLR->_parent = parent;
		subL->_right = parent;
		subL->_parent = parent->_parent;
		parent->_parent = subL;
		parent =subL;
		parent->bf = 0;
	}</span>


这种情况就是先左旋转然后右旋转,所以最初,我是这样写的

<span style="font-size:18px;">void _RotateLR(Node*& parent)
	{
		</span><pre name="code" class="cpp"><span style="font-size:18px;">               _RotateL(parent);</span>
<pre name="code" class="cpp"><span style="font-size:18px;">             _RotateR(parent);</span>

 
} 
 
但是,在某种特殊的情况下,它的平衡因子是不对的,所以我采用了,下面的办法补救

<span style="font-size:18px;">void _RotateLR(Node*& parent)
	{
		Node* pNode = parent;
		Node* subLNode = parent->_left;
		Node* subLRNode = subLNode->_right;
		int _bf = subLRNode->bf;

		_RotateL(parent->_left);
		_RotateR(parent);

		if (_bf == -1)
		{
			subLNode->bf = 0;
			pNode->bf = 1;
		}
		else if (_bf == 1)
		{
			subLNode->bf = -1;
			pNode->bf = 0;
		}
		else
		{
			subLNode->bf = 0;
			pNode->bf = 0;
		}

		subLRNode->bf = 0;
	}</span>


同理,我也就不把最初的代码给出来了,直接给新的

<span style="font-size:18px;">void _RotateRL(Node*& parent)
	{
		Node* pNode = parent;
		Node* subRNode = parent->_right;
		Node* subRLNode = subRNode->_left;
		int _bf = subRLNode->bf;

		_RotateR(parent->_right);
		_RotateL(parent);

		if (_bf == 1)
		{
			subRNode->bf = 0;
			pNode->bf = -1;
		}
		else if (_bf == -1)
		{
			subRNode->bf = 1;
			pNode->bf = 0;
		}
		else
		{	
			subRNode->bf = 0;
			pNode->bf = 0;
		}

		subRLNode->bf = 0;
	}</span>


接下来,我们说说它的删除

让节点D是我们要删除的节点,并让树中的节点E是一个节点我们需要找到节点D的位置,让节点N是我们拿出实际的节点树。
步骤时要考虑删除一个节点在一个AVL树如下:
1.如果节点D是一片叶子或只有一个孩子,跳到步骤6 N:= D、G D和的父母 dir 孩子的方向在G D。
2.否则,确定E的遍历的节点最左边的(最小) [9] D节点的右子树(D的顺序继承人−没有左子),或者最右边的在它的左子树(D的顺序的前任没有右子)。
3.记得节点G,E的父母。
4.提供节点E与所有节点D的孩子和家长联系,让节点E所有孩子和家长联系以前的新目标指向D在这一步中,节点之间的顺序序列D和E是暂时的干扰,但树结构并没有改变。
5.让N:= E, dir :=左)和F(左)孩子的E。
6.代替N在孩子的位置 dir 由其孩子F,G是null或叶。 在后一种情况下设置其母G。 
(现在的最后痕迹D已经从树中删除,所以D可能从内存中删除。)
7.如果节点N根(其母G是null),更新根。
8.Otherweise的高度 dir 子树G已经下降了1,从1到0或从2比1。 所以,让X:= G和N dir 孩子在下面的代码块(X),为了追溯路径备份根的树,从而调整平衡因素(包括可能的旋转)。


因为与单个删除AVL子树的高度不能减少一个以上的,暂时的平衡因素的一个节点将从−2 + 2。
如果平衡因素成为±2子树是不平衡的,需要旋转。 介绍了各种情况下的旋转部分 再平衡 。
通过删除节点N X的子树N的高度已经下降了1,从1到0或从2比1。


不变的追溯循环删除
由N棵子树的高度已经下降了1。 它已经在AVL形状。

<span style="font-size:18px;">for (X = parent(N); X != null; X = G) { // Loop (possibly up to the root)
     G = parent(X); // Save parent of X around rotations
     // BalanceFactor(X) has not yet been updated!
     if (N == left_child(X)) { // the left subtree decreases
         if (BalanceFactor(X) > 0) { // X is right-heavy
             // ===> the temporary BalanceFactor(X) == +2
             // ===> rebalancing is required.
             Z = right_child(X); // Sibling of N (higher by 2)
             b = BalanceFactor(Z);
             if (b < 0)                     // Right Left Case     (see figure 5)
                 N = rotate_RightLeft(X,Z); // Double rotation: Right(Z) then Left(X)
             else                           // Right Right Case    (see figure 4)
                 N = rotate_Left(X,Z);      // Single rotation Left(X)
             // After rotation adapt parent link
         }
         else {
             if (BalanceFactor(X) == 0) {
                 BalanceFactor(X) = +1; // N’s height decrease is absorbed at X.
                 break; // Leave the loop
             }
             N = X;
             BalanceFactor(N) = 0; // Height(N) decreases by 1
             continue;
         }
     }
     else { // (N == right_child(X)): The right subtree decreases
         if (BalanceFactor(X) < 0) { // X is left-heavy
             // ===> the temporary BalanceFactor(X) == –2
             // ===> rebalancing is required.
             Z = left_child(X); // Sibling of N (higher by 2)
             b = BalanceFactor(Z);
             if (b > 0)                     // Left Right Case
                 N = rotate_LeftRight(X,Z); // Double rotation: Left(Z) then Right(X)
                else                        // Left Left Case
                 N = rotate_Right(X,Z);     // Single rotation Right(X)
             // After rotation adapt parent link
         }
         else {
             if (BalanceFactor(X) == 0) {
                 BalanceFactor(X) = –1; // N’s height decrease is absorbed at X.
                 break; // Leave the loop
             }
             N = X;
             BalanceFactor(N) = 0; // Height(N) decreases by 1
             continue;
         }
     }
     // After a rotation adapt parent link:
     // N is the new root of the rotated subtree
     parent(N) = G;
     if (G != null) {
         if (X == left_child(G))
             left_child(G) = N;
         else
             right_child(G) = N;
         if (b == 0)
             break; // Height does not change: Leave the loop
     }
     else {
         tree->root = N; // N is the new root of the total tree
         continue;
     }
     // Height(N) decreases by 1 (== old Height(X)-1)
 }
 // Unless loop is left via break, the height of the total tree decreases by 1.</span>
追溯可以停止如果平衡因素变成了±1意味着子树的高度保持不变。
如果平衡因素变成了0,那么子树的高度降低,追溯需要继续。
如果暂时的平衡因素成为±2,这是修复了一个适当的旋转。 这取决于的平衡因子兄弟Z(更高的子树)是否子树的高度减少一个或不会改变(后者,如果Z因子平衡0)。
所需的时间是 O(log n ) 查找,再加上最多 O(log n ) 追溯水平( O(1) 平均)回到根,所以可以完成操作 O(log n ) 时间。
(ps:因为删除逻辑太多,所以以上是维基百科上的,网读者见谅)

AVL树和红黑树都是自平衡二叉搜索树,他们在数学上非常相似。 平衡树的操作不同,但平均发生 O(1) 最大的 O(log n ) 。 真正的两者之间的区别是极限高度。
树的大小 n ≥1


AVL树比“红-黑”树更严格的平衡,导致更快的检索,但缓慢的插入和删除。



完整的代码在点击打开链接





1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看rEADME.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看rEADME.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值