zoukankan      html  css  js  c++  java
  • 平衡二叉树算法分析

    1、平衡二叉树定义: 

    平衡二叉树(Balanced Binary Tree或Height-Balanced Tree)又称AVL树。它或者是一颗空树,或者是具有下列性质的二叉树:它的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值不超过1。若将二叉树上结点的平衡因子bf(balance factor)定义为该结点的左子树的深度减去右子树的深度,则平衡二叉树上所有结点的平衡因子只可能为-1、0和1这三个值。

    2、失去平衡情况分析:

    假设结点A是一颗子平衡二叉树,当在以A为根结点的AVL树上插入一个新结点时,会出现以下三种情况:

    1)如果插入前A—>bf=1(A的左子树深度比右子树深度多1),如果插入在A的左子树上且A的左子树深度增加了1,则此时A—>bf=2需要对树进行调整,如图2.1结点C为新插入的结点,C可以插入到B的左子树上(如图2.1(b))或者右子树上(如图2.1(c))。

    2)如果插入前A—>bf=0(A的左子树和右子树深度相等),如果插入在A的左子树上且A的左子树深度增加了1,则此时只需要改变A的平衡因子为1即可不需要对树进行调整。如果插入在A的右子树上且A的右子树深度增加了1,则此时只需要改变A的平衡因子为-1即可不需要进行调整。

    3)如果插入前A—>bf=-1(A的左子树深度比右子树深度少1),如果插入在A的右子树上且A的右子树深度增加了1,则此时A—>bf=-2需要对树进行调整,如图2.2结点C为新插入的结点,C可以插入在B的左子树上(如图2.2(b))或者右子树上(如图2.2(c))。

                                

                         图2.1                                                   图2.2

                注意:上图中为了清楚的看到添加结点后失去平衡时的情况,省去了一些子结点,这些结点在下面的分析中会完整画出来

    当出现图2.1(b)中的情况时只需要进行一次右旋转操作,旋转后得到如图2.1(d)所示的平衡二叉树。

    当出现图2.1(c)中的情况时需要先对A的左子树B进行左旋操作,然后再进行右旋操作,旋转后得到如图2.1(e)所示的平衡二叉树。

    当出现图2.2(b)中的情况时只需要进行一次右旋转操作,旋转后得到如图2.1(d)所示的平衡二叉树。

    当出现图2.2(c)中的情况时需要先对A的右子树B进行右旋,然后再进行左旋操作,旋转后得到如图2.2(e)所示的平衡二叉树。

    3.求旋转后各结点的平衡因子:

    旋转后怎么确定各结点的新的平衡因子是平衡二叉树算法的关键点,我们需要按情况来一一推理。

    一、当出现图2.1(b)(c)这两种情况时,需进行左平衡处理:

    1)当新结点插入到B的左子树上时B—>bf=1,由此可知:deep(C)=deep(E)+1,deep(B)=deep(C)+1;由于插入新结点前A—>bf=1,deep(B)=deep(D)+1则插入新节点后deep(B)=deep(D)+2;图3.1.1为调整前的二叉树,图3.1.2为对A树进行右旋转后的AVL树:

                                                  

                    图3.1.1                                                                                                         图3.1.2

    对比图3.1.1和3.1.2可知旋转后的新树中A的左子树发生了变化,B的右子树发生了变化,其他结点都没变;因此只需要重新算出A的平衡因子和B的平衡因子即可证明调整后的树是否为AVL树。

    由上面的等式deep(B)=deep(D)+2,deep(B)=deep(C)+1,deep(C)=deep(E)+1

    可以推出deep(E)=deep(C)-1=deep(B)-1-1=deep(D)+2-1-1=deep(D)可得出A—>bf=0

    由调整后deep(E)=deep(D)可推出调整后deep(A)=deep(E)+1=deep(C)-1+1=deep(C)可得出B—>bf=0;

    2)当新结点插入到B的右子树上时B—>bf=-1,由此可知:deep(C)=deep(E)-1,deep(B)=deep(E)+1;由于插入新结点前A—>bf=1,deep(B)=deep(D)+1则插入新节点后deep(B)=deep(D)+2图3.2.1为调整前的二叉树,图3.2.2为先对B树进行左旋然后对A树进行右旋后的AVL树:

                                                          

                      图3.2.1                                                                                                                                 图3.2.2

    对比图3.2.1和3.2.2可知调整后的新树中A的左子树发生了变化,B的右子树发生了变化,E的左右子树都发生了变化,其他结点都没变,因此只需要重新算出A的平衡因子、B的平衡因子以及E的平衡因子即可证明调整后的树是否为AVL树。

    此时由于调整后的B和A结点的平衡因子与E的左右子树EL和ER有关,因此需要根据E的平衡因子的不同来进行分析:

    由上面的分析可得到deep(B)=deep(D)+2,deep(B)=deep(E)+1,deep(C)=deep(E)-1

    1、当E—>bf=1时:deep(E)=deep(EL)+1,deep(ER)=deep(EL)-1

    deep(C)=deep(E)-1=deep(EL)+1-1=deep(EL)可得B—>bf=0

    deep(D)=deep(B)-2=deep(E)+1-2=deep(ER)+1+1+1-2=deep(ER)+1可得A—>bf=-1

    由于deep(EL)=deep(ER)+1所以E—>bf=0

    2、当E—>bf=0时:deep(E)=deep(EL)+1,deep(ER)=deep(EL)

    deep(C)=deep(E)-1=deep(EL)+1-1=deep(EL)可得B—>bf=0

    deep(D)=deep(B)-2=deep(E)+1-2=deep(ER)+1+1-2=deep(ER)可得A—>bf=0

    由于B—>bf=0,A—>bf=0所以E—>bf=0

    3、当E—>bf=-1时:deep(E)=deep(ER)+1,deep(ER)=deep(EL)+1

    deep(C)=deep(E)-1=deep(EL)+1+1-1=deep(EL)+1可得B—>bf=1

    deep(D)=deep(B)-2=deep(E)+1-2=deep(ER)+1+1-2=deep(ER)可得A—>bf=0

    由于deep(EL)=deep(ER)-1所以E—>bf=0

    二、当出现图2.2(b)(c)这两种情况时,需进行右平衡处理:

    1)当新结点插入到C的左子树上时C—>bf=1,由此可知:deep(C)=deep(E)+1,deep(D)=deep(E)-1;由于插入新结点前A—>bf=-1,deep(B)=deep(C)-1则插入新节点后deep(B)=deep(C)-2图3.3.1为调整前的二叉树,图3.3.2为先对C树进行右旋然后对A树进行左旋后的AVL树:

                                                        

                      图3.3.1                                                                                                           图3.3.2 

    对比图3.3.1和3.3.2可知调整后的新树中A的右子树发生了变化,C的左子树发生了变化,E的左右子树都发生了变化,其他结点都没变,因此只需要重新算出A的平衡因子、B的平衡因子以及E的平衡因子即可证明调整后的树是否为AVL树。

    此时由于调整后的A和C结点的平衡因子与E的左右子树EL和ER有关,因此需要根据E的平衡因子的不同来进行分析:

    由上面的分析可得到deep(B)=deep(C)-2,deep(C)=deep(E)+1,deep(D)=deep(E)-1

    1、当E—>bf=1时:deep(E)=deep(EL)+1,deep(ER)=deep(EL)-1

    deep(B)=deep(C)-2=deep(EL)+1+1-2=deep(EL)可得A—>bf=0

    deep(D)=deep(E)-1=deep(ER)+1+1-1=deep(ER)+1可得C—>bf=-1

    由于deep(EL)=deep(ER)+1所以E—>bf=0

    2、当E—>bf=0时:deep(E)=deep(EL)+1,deep(ER)=deep(EL)

    deep(B)=deep(E)+1-2=deep(EL)+1+1-2=deep(EL)可得A—>bf=0

    deep(D)=deep(E)-1=deep(ER)+1-1=deep(ER)可得C—>bf=0

    由于A—>bf=0,C—>bf=0所以E—>bf=0

    3、当E—>bf=-1时:deep(E)=deep(ER)+1,deep(ER)=deep(EL)+1

    deep(B)=deep(C)-2=deep(E)+1-2=deep(EL)+1+1+1-2=deep(EL)+1可得A—>bf=1

    deep(D)=deep(E)-1=deep(ER)+1-1=deep(ER)可得C—>bf=0

    由于deep(EL)=deep(ER)-1所以E—>bf=0

     

    2)当新结点插入到C的右子树上时C—>bf=-1,由此可知:deep(C)=deep(D)+1,deep(D)=deep(E)+1;由于插入新结点前A—>bf=-1,deep(B)=deep(C)-1则插入新节点后deep(B)=deep(C)-2图3.4.1为调整前的二叉树,图3.4.2为进行左旋后的AVL树:

                                                       

                               图3.4.1                                                      图3.4.2

    对比图3.4.1和3.4.2可知调整后的新树中A的右子树发生了变化,C的左子树发生了变化,其他结点都没变,因此只需要重新算出A的平衡因子和C的平衡因子即可证明调整后的树是否为AVL树。

    由上面的等式deep(B)=deep(C)-2,deep(C)=deep(D)+1,deep(D)=deep(E)+1

    可以推出deep(B)=deep(C)-2=deep(D)+1-2=deep(E)+1+1-2=deep(E)可得出A—>bf=0

    由A—>bf=0调整后deep(A)=deep(E)+1=deep(D)-1+1=deep(D)可得出C—>bf=0;

    4.Java实现代码:

      1 package org.algorithms.tree;
      2 
      3 import java.util.concurrent.ConcurrentLinkedQueue;
      4 
      5 
      6 public class BalanceBiTree<T> {
      7 
      8     private Node root;
      9     
     10     private int size;
     11     
     12     public void insert(T t){
     13         if(root==null){
     14             root = new Node();
     15             root.bf = 0;
     16             root.data = t;
     17             size++;
     18             return;
     19         }
     20         addNode(root,t);
     21     }
     22     
     23     private boolean addNode(Node nd,T t){
     24         boolean taller = false;
     25         Comparable<T> cp = (Comparable<T>)nd.data;
     26         int i = cp.compareTo(t);
     27         if(i==0){
     28             return false;
     29         }else if(i>0){
     30             if(nd.lChild==null){
     31                 Node child = new Node();
     32                 child.bf = 0;
     33                 child.data = t;
     34                 child.parent = nd;
     35                 nd.lChild = child;
     36                 size++;
     37                 if(nd.bf==0){
     38                     nd.bf = 1;
     39                     return true;
     40                 }
     41                 nd.bf = 0;
     42             }else{
     43                 taller = addNode(nd.lChild, t);
     44                 if(taller){
     45                     if(nd.bf==1){
     46                         leftBalance(nd);
     47                         taller = false;
     48                     }else if(nd.bf==0){
     49                         nd.bf = 1;
     50                         taller = true;
     51                     }else{
     52                         nd.bf = 0;
     53                         taller = false;
     54                     }
     55                 }
     56             }
     57         }else{
     58             if(nd.rChild==null){
     59                 Node child = new Node();
     60                 child.bf = 0;
     61                 child.data = t;
     62                 child.parent = nd;
     63                 nd.rChild = child;
     64                 size++;
     65                 if(nd.bf==0){
     66                     nd.bf = -1;
     67                     return true;
     68                 }
     69                 nd.bf = 0;
     70             }else{
     71                 taller = addNode(nd.rChild, t);
     72                 if(taller){
     73                     if(nd.bf==1){
     74                         nd.bf = 0;
     75                         taller = false;
     76                     }else if(nd.bf==0){
     77                         nd.bf = -1;
     78                         taller = true;
     79                     }else{
     80                         rightBalance(nd);
     81                         taller = false;
     82                     }
     83                 }
     84             }
     85         }
     86         return taller;
     87     }
     88     
     89     public int getSize(){
     90         return size;
     91     }
     92     
     93     private void leftBalance(Node nd){
     94         Node leftChild = nd.lChild;
     95         if(leftChild.bf==1){
     96             nd.bf = 0;
     97             leftChild.bf = 0;
     98             rightRotate(nd);
     99         }else if(leftChild.bf==-1){
    100             Node rd = leftChild.rChild;
    101             switch (rd.bf) {
    102             case 1:
    103                 leftChild.bf=0;nd.bf = -1;
    104                 break;
    105             case 0:
    106                 leftChild.bf=0;nd.bf = 0;
    107                 break;
    108             case -1:
    109                 leftChild.bf = 1;nd.bf = 0;
    110                 break;
    111             }
    112             rd.bf = 0 ;
    113             leftRotate(leftChild);
    114             rightRotate(nd);
    115         }
    116     }
    117     
    118     private void rightBalance(Node nd){
    119         Node rightChild = nd.rChild;
    120         if(rightChild.bf==1){
    121             Node ld = rightChild.lChild;
    122             switch (ld.bf) {
    123             case 1:
    124                 rightChild.bf= -1; nd.bf = 0;
    125                 break;
    126             case 0:
    127                 rightChild.bf=0;nd.bf = 0;
    128                 break;
    129             case -1:
    130                 rightChild.bf = 0;nd.bf = 1;
    131                 break;
    132             }
    133             ld.bf = 0 ;
    134             rightRotate(rightChild);
    135             leftRotate(nd);
    136         }else if(rightChild.bf==-1){
    137             nd.bf = 0;
    138             rightChild.bf = 0;
    139             leftRotate(nd);
    140         }
    141         
    142     }
    143     
    144     private void leftRotate(Node nd){
    145         Node top = nd.rChild;
    146         nd.rChild = top.lChild;
    147         if(top.lChild!=null)
    148             top.lChild.parent = nd;
    149         top.lChild = nd;
    150         top.parent = nd.parent;
    151         if(nd.parent!=null){
    152             if(nd.parent.lChild == nd)
    153                 nd.parent.lChild = top;
    154             else
    155                 nd.parent.rChild = top;
    156         }else{
    157             root = top;
    158         }
    159         nd.parent = top;
    160     }
    161     
    162     private void rightRotate(Node nd){
    163         Node top = nd.lChild;
    164         nd.lChild = top.rChild;
    165         if(top.rChild!=null)
    166             top.rChild.parent = nd;
    167         top.rChild = nd;
    168         top.parent = nd.parent;
    169         if(nd.parent!=null){
    170             if(nd.parent.lChild == nd)
    171                 nd.parent.lChild = top;
    172             else
    173                 nd.parent.rChild = top;
    174         }else{
    175             root = top;
    176         }
    177         nd.parent = top;
    178     }
    179     
    180     public void printTree(){
    181         ConcurrentLinkedQueue<Node> queue = new ConcurrentLinkedQueue<Node>();
    182         ConcurrentLinkedQueue<Node> tempQueue = new ConcurrentLinkedQueue<Node>();
    183         queue.add(root);
    184         int offset= 0;
    185         int counter=2;
    186         for(int i=0;i<50;i++)
    187             System.out.print(" ");
    188         while(queue.peek()!=null){
    189             Node node = queue.poll();
    190             String side = "L";
    191             if(node.parent!=null&&node.parent.rChild==node)
    192                 side = "R";
    193             System.out.print(node.data+"("+(node.parent==null?"":node.parent.data)+" "+side+")");
    194             if(node.parent!=null&&node.parent.rChild!=node)
    195                 for(int i=0;i<counter;i++)
    196                     System.out.print(" ");
    197             if(node.lChild!=null)
    198                 tempQueue.add(node.lChild);
    199             if(node.rChild!=null)
    200                 tempQueue.add(node.rChild);
    201             if(queue.isEmpty()){
    202                 offset += 3;
    203                 //counter--;
    204                 copyQueue(tempQueue,queue);
    205                 System.out.println();
    206                 for(int i=0;i<50-offset;i++)
    207                     System.out.print(" ");
    208             }
    209         }
    210         
    211     }
    212     
    213     private void copyQueue(ConcurrentLinkedQueue<Node> source,
    214             ConcurrentLinkedQueue<Node> target){
    215         while(source.peek()!=null){
    216             target.add(source.poll());
    217         }
    218     }
    219     
    220     private class Node{
    221         
    222         public T data;
    223         
    224         public Node lChild;
    225         
    226         public Node rChild;
    227         
    228         public Node parent;
    229         
    230         public int bf;
    231     }
    232 }

     

  • 相关阅读:
    没有被实例化的类 中的 非static成员函数竟然也可以被调用。。。前提是该成员函数没有用到成员变量
    c++注意
    关于类大小的小试验
    C语言|博客作业02
    在C#中进行时间和时间戳的转换
    正则表达式中匹配中括号 [ ]
    在C#中将对象序列化成Json格式
    在MSSQL中的简单数据类型递归
    HTML中padding和margin的区别和用法
    C#中的对称加密
  • 原文地址:https://www.cnblogs.com/javaminer/p/3462468.html
Copyright © 2011-2022 走看看