AVL平衡二叉树图解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
//  AVLTree插入算法
template < class  K,  class  V>
bool  AVLTree<K,V>::Insert( const  K& key,  const  V& value)
{
     //1.空树
     if  (_root == NULL)
     {
         _root =  new  AVLTreeNode<K, V>(key, value);
         return  true ;
     }
     
     //2.AVL树不为NULL
     AVLTreeNode<K, V>* parent = NULL;
     AVLTreeNode<K, V>* cur = _root;
     //找到数据插入位置
     while  (cur)
     {
         if  (cur->_key < key)
         {
             parent = cur;
             cur = cur->_right;
         }
         else     if  (cur->_key > key)
         {
             parent = cur;
             cur = cur->_left;
         }
         else
         {
             return  false ;
         }
     }
     //插入数据
         cur =  new  AVLTreeNode<K, V>(key, value);
         cur->_parent = parent;
         if  (parent->_key > key)
             parent->_left = cur;
         else
             parent->_right = cur;
 
         while  (parent)
         {
             //更新平衡因子
             if  (cur == parent->_left)
                 parent->_bf--;
             else  if  (cur == parent->_right)
                 parent->_bf++;
 
             //检验平衡因子是否合法
             if  (parent->_bf == 0)
                 break ;
             else  if  (parent->_bf == -1 || parent->_bf == 1)
             {   // 回溯上升 更新祖父节点的平衡因子并检验合法性
                 cur = parent;
                 parent = cur->_parent;
             }
             else   //  2 -2 平衡因子不合法 需要进行旋转 降低高度
             {
                 if  (parent->_bf == 2)
                 {
                     if  (cur->_bf == 1)
                         _RotateL(parent);
                     else
                         _RotateRL(parent);
                 }
                 else  if  (parent->_bf == -2)
                 {
                     if  (cur->_bf == -1)
                         _RotateR(parent);
                     else
                         _RotateLR(parent);
                 }
                 break ;
             }
         }
}

   


左旋的两种情况:

1.parent有两个孩子:没有插入节点c之前处于平衡状态,插入c之后,平衡被破坏,向上回溯检验祖父节点的平衡因子,当其bf=2 时,以此节点为轴进行左旋

2.parent有一个孩子:没有插入节点a之前处于平衡状态,插入节点a之后,parent节点的平衡因子bf=2不满足AVL树的性质,要以parent为轴进行左旋

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//左旋
template < class  K,  class  V>
void  AVLTree<K, V>::_RotateL(AVLTreeNode<K, V>*&  parent)
{
     AVLTreeNode<K, V>* subR = parent->_right;
     AVLTreeNode<K, V>* subRL = subR->_left;
     AVLTreeNode<K, V>* ppNode = parent->_parent;       //标记祖先节点
 
     //1.构建parent子树 链接parent和subRL
     parent->_right = subRL;
     if  (subRL) subRL->_parent = parent;
     //2.构建subR子树 链接parent和subR
     subR->_left = parent;
     parent->_parent = subR;
     //3.链接祖先节点和subR节点
     subR->_parent = ppNode;
     if  (ppNode== NULL)
     { //如果祖先节点为NULL,说明目前的根节点为subR
         _root = subR;
     }
     else
     {   //将祖先节点和subR节点链接起来
         if  (parent == ppNode->_left)
             ppNode->_left = subR;
         else
             ppNode->_right = subR;
     }
     //4.重置平衡因子
     parent->_bf = 0;
     subR->_bf = 0;
     //5.更新subR为当前父节点
     parent = subR;
}

右旋的两种情况:

1. parent既有左孩子又有右孩子:插入c之前处于平衡态,插入c之后parent的平衡因子变为-2,这时要以parent为轴进行旋转

 

2. parent只有一个孩子:插入a之前处于平衡状态,插入之后subL与parent的平衡因子被改变,需要以parent为轴进行旋转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
///右旋
template < class  K,  class  V>
void  AVLTree<K, V>::_RotateR(AVLTreeNode<K, V>*&  parent)
{
     AVLTreeNode<K, V>* subL = parent->_left;
     AVLTreeNode<K, V>* subLR = subL->_right;
     AVLTreeNode<K, V>* ppNode = parent->_parent;       //标记祖先节点
     //1.构建parent子树 将parent和subLR链接起来
     parent->_left = subLR;
     if  (subLR) subLR->_parent = parent;
     //2.构建subL子树 将subL与parent链接起来
     subL->_right = parent;
     parent->_parent = subL;
     //3.将祖先节点与sunL链接起来
     if  (ppNode == NULL)
     {   //如果祖先为NULL,说明当前subL节点为根节点
         subL->_parent = NULL;
         _root = subL;
     }
     else
     {
         subL->_parent = ppNode;
         if  (ppNode->_left == parent)
             ppNode->_left = subL;
         else  if  (ppNode->_right == parent)
             ppNode->_right = subL;
     }
     //4.重置平衡因子
     parent->_bf = 0;
     subL->_bf = 0;
     //5.更新subL为当前父节点
     parent = subL;
}

 左右双旋:

1. parent只有一个孩子:在插入节点sunLR之前,AVL树处于平衡状态,左右子树高度差的绝对值不超过1。

  由于插入了节点subLR导致grandfather的平衡因子变为-2,平衡树失衡,所以需要利用旋转来降低高度!

  • 首先以subL为轴,将subLR向上提(左旋),将grandfather、parent和subL旋转至一条直线上;
  • 再以parent为轴将之前的subLR向上提(右旋),左树的高度降1,grandfather的平衡因子加1后变为-1,恢复平衡状态。
  • 双旋完成后将parent、subL的平衡因子置为0即可,左右双旋也就完成啦!

2. parent有两个孩子:没有插入subRL或subRR之前的AVL树一定是处于平衡状态的,并且满足AVL树的性质。

  正是由于插入了节点subRL或者subRR,导致其祖先节点的平衡因子被改变,grandfather的平衡因子变为-2,平衡态比打破,需要进行旋转来降低高度!

  • 首先parent为轴将subR节点往上提至原parent的位置(左旋),将grandfather、parent 和 subR旋至一条直线上;
  • 再以grandfather为轴将subR往上提至grandfather的位置(右旋),此时以subR为根的左右子树的高度相同,恢复了平衡态!

parent有两个孩子时,要看插入的节点是subR的右孩子还是左孩子,双旋后对平衡因子的修改分两种情况:

  • subR的平衡因子为1,即subR有右孩子无左孩子(有subRR但无subRL),双旋之后将grandfather的平衡因子置为0,将parent的平衡因子置为-1;
  • subR的平衡因子为-1,即subR有左孩子无右孩子(有subRL但无subRR),双旋之后将grandfather的平衡因子置为1,将parent的平衡因子置为0;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//左右双旋
template < class  K,  class  V>
void  AVLTree<K, V>::_RotateLR(AVLTreeNode<K, V>*&  parent)
{
     AVLTreeNode<K, V>* pNode = parent;
     AVLTreeNode<K, V>* subL = parent->_left;
     AVLTreeNode<K, V>* subLR = subL->_right;
     int  bf = subLR->_bf;
 
     _RotateL(parent->_left);
     _RotateR(parent);
     
     if  (bf == 1)
     {
         pNode->_bf = 0;
         subL->_bf = -1;
     }
     else  if  (bf == -1)
     {
         pNode->_bf = 1;
         subL->_bf = 0;
     }
     else
     {
         pNode->_bf = 0;
         subL->_bf = 0;
     }
 
}

 右左双旋:

1. parent只有一个孩子:由于节点subRL的插入破坏了AVL树的平衡,parent的平衡因子变为2,需要利用旋转来降低高度!

  • 首先,以subR为轴,将subRL提上去(右旋),保证parent、subR 和 subRL在一条直线上;
  • 以parent为轴,将上一步标记为subRL的节点向上升(左旋),这样达到了降低高度的目的;
  • 双旋之后,parent和subR的平衡因子都要置为0

 

2.parent有两个孩子:没有插入subLL或者subLR之前的AVL树一定是处于平衡状态的,并且满足AVL树的性质。

  正是由于插入了节点subLL或者subLR,导致其祖先节点的平衡因子被改变,grandfather的平衡因子变为2,平衡态比打破,需要进行旋转来降低高度!

  • 首先parent为轴将subL节点往上提至原parent的位置(右旋),将grandfather、parent 和 subL旋至一条直线上;
  • 再以grandfather为轴将subL往上提至grandfather的位置(左旋),此时以subL为根的左右子树的高度相同,恢复了平衡态!

parent有两个孩子时,要看插入的节点是subL的右孩子还是左孩子,双旋后对平衡因子的修改分两种情况:

  • subL的平衡因子为1,即subL有右孩子无左孩子(有subLR但无subLL),双旋之后将grandfather的平衡因子置为-1,将parent的平衡因子置为0;
  • subL的平衡因子为-1,即subL有左孩子无右孩子(有subLL但无subLR),双旋之后将grandfather的平衡因子置为0,将parent的平衡因子置为1; 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//右左双旋
template < class  K,  class  V>
void  AVLTree<K, V>::_RotateRL(AVLTreeNode<K, V>*&  parent)
{
     AVLTreeNode<K, V>* pNode = parent;
     AVLTreeNode<K, V>* subR= parent->_right;
     AVLTreeNode<K, V>* subRL = subR->_left;
     int  bf = subRL->_bf;
 
     _RotateR(parent->_right);
     _RotateL(parent);
 
     if  (bf == 1)
     {
         pNode->_bf = 0;
         subR->_bf = -1;
     }
     else  if  (bf == -1)
     {
         pNode->_bf = 1;
         subR->_bf = 0;
     }
     else
     {
         pNode->_bf = 0;
         subR->_bf = 0;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值