• 数据结构


    平衡二叉树是在二叉搜索树的基础上增加了结构变换,理解起来费劲不少。

    四种转换类型:LL、RR、RL、LR

    要理解这四种类型,需要先说明一个概念:

    平衡系数:Balance Fate(以下简称BF)

    算法是:拿到一个节点,求这个节点左子树与右子树的深度差的绝对值。

    对于平衡二叉树有3种情况:0、1、2,其中2就代表失衡状态,需要转换结构。

    从BF为2的节点向下追踪2层,朝着深度深的方向追。就出现了4种情况:

    高能预警:

    LL:BFnode - BFnode.leftchild - BFnode.leftchild.leftchild (左左)

    处理方式:交换BFnode和BFnode.leftchild

    RR:BFnode - BFnode.rightchild - BFnode.rightchild.rightchild (右右)

    处理方式:交换BFnode和BFnode.rightchild

    LR:BFnode - BFnode.leftchild - BFnode.leftchild.rightchild (左右)

    处理方式:交换BFnode和BFnode.leftchild.rightchild

    RL:BFnode - BFnode.rightchild - BFnode.rightchild.leftchild (右左)

    处理方式:交换BFnode和BFnode.rightchild.leftchild

    添加元素的思路:

    将元素添加到对应位置,向上追溯到根节点,判断当前节点的BF,如果等于2就判断类型,并根据类型进行转换。

    删除元素的思路:

    找到要删除的节点,再找到删除元素左子树的最右节点(可能不是叶子节点),用最右节点替换要删除的节点,并从最右节点的父节点向上追溯到根节点,判断当前节点的BF,如果等于2就判断类型,并根据类型进行转换。

    上代码:(并未经过严格测试,参考网上资料,基于个人理解,供学习使用)

      1 package collections;
      2 
      3 public class AVLTree {
      4 
      5     private AVLNode root;
      6 
      7     // delete node
      8     public void delete(int val) {
      9         if (root == null) {
     10             return;
     11         }
     12         AVLNode delNode = get(val);
     13         if (delNode == null) {
     14             return;
     15         }
     16         AVLNode replaceNode = findRightLeaf(delNode.leftChild);
     17         AVLNode tracebackNode;
     18         // delete node self
     19         // null means left child is null
     20         // contain leaf condition
     21         if (replaceNode == null) {
     22             AVLNode rightChild = delNode.rightChild;
     23             setChild(setParent(rightChild, delNode), delNode, rightChild);
     24             tracebackNode = delNode;
     25         } else {
     26             tracebackNode = replaceDeleteNode(delNode, replaceNode);
     27         }
     28         // trace back to root
     29         tracebackAndConvert(tracebackNode);
     30         // clear delete node
     31         delNode.parent = null;
     32         delNode.leftChild = null;
     33         delNode.rightChild = null;
     34     }
     35 
     36     // check weather the tree has val
     37     public boolean contain(int val) {
     38         return get(val) != null;
     39     }
     40 
     41     // get node by value
     42     public AVLNode get(int val) {
     43         if (root == null) {
     44             return null;
     45         }
     46         return get(val, root);
     47     }
     48 
     49     // add value
     50     public void add(int val) {
     51         if (root == null) {
     52             root = new AVLNode(val);
     53             return;
     54         }
     55         AVLNode insertNode = new AVLNode(val);
     56         AVLNode node = root;
     57         while (true) {
     58             if (val <= node.val) {
     59                 if (node.leftChild == null) {
     60                     insertNode.parent = node;
     61                     node.leftChild = insertNode;
     62                     break;
     63                 }
     64                 node = node.leftChild;
     65             } else {
     66                 if (node.rightChild == null) {
     67                     insertNode.parent = node;
     68                     node.rightChild = insertNode;
     69                     break;
     70                 }
     71                 node = node.rightChild;
     72             }
     73         }
     74         tracebackAndConvert(insertNode);
     75     }
     76 
     77     // degree left right print
     78     public void showDLR() {
     79         iteratorDLR(root);
     80     }
     81 
     82     // left degree right print
     83     public void showLDR() {
     84         iteratorLDR(root);
     85     }
     86 
     87     // left right degree print
     88     public void showLRD() {
     89         iteratorLRD(root);
     90     }
     91 
     92     // check empty
     93     public boolean isEmpty() {
     94         return getDepth(root) == 0;
     95     }
     96 
     97     // get tree depth
     98     public int depth() {
     99         return getDepth(root);
    100     }
    101 
    102     // trace back to root and convert structure
    103     private void tracebackAndConvert(AVLNode tracebackNode) {
    104         while (true) {
    105             if (getBF(tracebackNode) == 2) {
    106                 // convert structure
    107                 convert(tracebackNode);
    108             }
    109             if (tracebackNode == root) {
    110                 break;
    111             }
    112             tracebackNode = tracebackNode.parent;
    113         }
    114     }
    115 
    116     // convert structure
    117     private void convert(AVLNode convertNode) {
    118         StringBuilder sign = new StringBuilder();
    119         AVLNode node = getNodeAndRotateType(convertNode, sign);
    120         switch (sign.toString()) {
    121             case "ll":
    122                 rotateLL(convertNode);
    123                 break;
    124             case "rr":
    125                 rotateRR(convertNode);
    126                 break;
    127             case "lr":
    128                 rotateLR(node, convertNode);
    129                 break;
    130             case "rl":
    131                 rotateRL(node, convertNode);
    132                 break;
    133         }
    134     }
    135 
    136     // get node and rotate type
    137     private AVLNode getNodeAndRotateType(AVLNode node, StringBuilder sign) {
    138         for (int i = 0; i < 2; i++) {
    139             // means left child lose balance
    140             if (getDepth(node.leftChild) > getDepth(node.rightChild)) {
    141                 sign.append('l');
    142                 node = node.leftChild;
    143             }
    144             // means right child lose balance
    145             if (getDepth(node.rightChild) > getDepth(node.leftChild)) {
    146                 sign.append('r');
    147                 node = node.rightChild;
    148             }
    149         }
    150         return node;
    151     }
    152 
    153     // replace delete node
    154     private AVLNode replaceDeleteNode(AVLNode deleteNode, AVLNode replaceNode) {
    155         AVLNode replaceNodeParent = replaceNode.parent;
    156         AVLNode replaceNodeLeftChild = replaceNode.leftChild;
    157         if (replaceNodeParent.leftChild == replaceNode) {
    158             replaceNodeParent.leftChild = replaceNodeLeftChild;
    159         } else {
    160             replaceNodeParent.rightChild = replaceNodeLeftChild;
    161         }
    162         if (replaceNodeLeftChild != null) {
    163             replaceNodeLeftChild.parent = replaceNodeParent;
    164         }
    165         AVLNode deleteParent = deleteNode.parent;
    166         AVLNode tracebackNode = replaceNode.parent;
    167         replaceNode.parent = deleteParent;
    168         if (deleteParent.leftChild == deleteNode) {
    169             deleteParent.leftChild = replaceNode;
    170         } else {
    171             deleteParent.rightChild = replaceNode;
    172         }
    173         // the replace node is the left child of delete node
    174         if (deleteNode.leftChild == replaceNode) {
    175             replaceNode.leftChild = null;
    176         } else {
    177             replaceNode.leftChild = deleteNode.leftChild;
    178         }
    179         replaceNode.rightChild = deleteNode.rightChild;
    180         return tracebackNode;
    181     }
    182 
    183     // find the right leaf which should replace the removed node
    184     private AVLNode findRightLeaf(AVLNode node) {
    185         if (node == null) {
    186             return null;
    187         }
    188         if (node.rightChild == null) {
    189             return node;
    190         }
    191         return findRightLeaf(node.rightChild);
    192     }
    193 
    194     private AVLNode get(int val, AVLNode node) {
    195         if (node == null) {
    196             return null;
    197         }
    198         if (val < node.val) {
    199             return get(val, node.leftChild);
    200         } else if (val > node.val) {
    201             return get(val, node.rightChild);
    202         } else {
    203             return node;
    204         }
    205     }
    206 
    207     private void iteratorDLR(AVLNode node) {
    208         if (node == null) {
    209             return;
    210         }
    211         System.out.print(node.val + ",");
    212         iteratorDLR(node.leftChild);
    213         iteratorDLR(node.rightChild);
    214     }
    215 
    216     private void iteratorLDR(AVLNode node) {
    217         if (node == null) {
    218             return;
    219         }
    220         iteratorLDR(node.leftChild);
    221         System.out.print(node.val + ",");
    222         iteratorLDR(node.rightChild);
    223     }
    224 
    225     private void iteratorLRD(AVLNode node) {
    226         if (node == null) {
    227             return;
    228         }
    229         iteratorLRD(node.leftChild);
    230         iteratorLRD(node.rightChild);
    231         System.out.print(node.val + ",");
    232     }
    233 
    234     // ll rotate
    235     private void rotateLL(AVLNode convertNode) {
    236         AVLNode node = convertNode.leftChild;
    237         setChild(setParent(node, convertNode), convertNode, node);
    238         convertNode.leftChild = node.rightChild;
    239         node.rightChild = convertNode;
    240         convertNode.parent = node;
    241     }
    242 
    243     // rr rotate
    244     private void rotateRR(AVLNode convertNode) {
    245         AVLNode node = convertNode.rightChild;
    246         setChild(setParent(node, convertNode), convertNode, node);
    247         convertNode.rightChild = node.leftChild;
    248         node.leftChild = convertNode;
    249         convertNode.parent = node;
    250     }
    251 
    252     // rl rotate
    253     private void rotateRL(AVLNode node, AVLNode convertNode) {
    254         setChild(setParent(node, convertNode), convertNode, node);
    255         AVLNode rightChild = convertNode.rightChild;
    256         rightChild.parent = node;
    257         rightChild.leftChild = null;
    258         node.leftChild = convertNode;
    259         node.rightChild = rightChild;
    260         convertNode.parent = node;
    261         convertNode.rightChild = null;
    262     }
    263 
    264     // lr rotate
    265     private void rotateLR(AVLNode node, AVLNode convertNode) {
    266         setChild(setParent(node, convertNode), convertNode, node);
    267         AVLNode leftChild = convertNode.leftChild;
    268         leftChild.parent = node;
    269         leftChild.rightChild = null;
    270         node.leftChild = leftChild;
    271         node.rightChild = convertNode;
    272         convertNode.parent = node;
    273         convertNode.leftChild = null;
    274     }
    275 
    276     private AVLNode setParent(AVLNode node, AVLNode convertNode) {
    277         AVLNode parent = convertNode.parent;
    278         if (node != null) {
    279             node.parent = parent;
    280         }
    281         return parent;
    282     }
    283 
    284     private void setChild(AVLNode parent, AVLNode originChild, AVLNode newChild) {
    285         if (parent == null) {
    286             root = newChild;
    287             return;
    288         }
    289         if (parent.leftChild == originChild) {
    290             parent.leftChild = newChild;
    291         } else {
    292             parent.rightChild = newChild;
    293         }
    294     }
    295 
    296     // get balance fate
    297     private int getBF(AVLNode node) {
    298         if (node == null) {
    299             return 0;
    300         }
    301         return Math.abs(getDepth(node.leftChild) - getDepth(node.rightChild));
    302     }
    303 
    304     // get node depth
    305     private int getDepth(AVLNode node) {
    306         if (node == null) {
    307             return 0;
    308         }
    309         return 1 + Math.max(getDepth(node.leftChild), getDepth(node.rightChild));
    310     }
    311 
    312     public static void main(String[] args) {
    313         AVLTree tree = new AVLTree();
    314         tree.add(25);
    315         tree.add(30);
    316         tree.add(35);
    317         tree.add(45);
    318         tree.add(40);
    319         tree.add(50);
    320         tree.add(47);
    321         tree.showDLR();
    322         System.out.println();
    323         tree.delete(47);
    324         tree.showDLR();
    325         System.out.println();
    326         tree.add(20);
    327         tree.showDLR();
    328     }
    329 
    330 }
    331 
    332 class AVLNode {
    333     AVLNode parent;
    334     AVLNode leftChild;
    335     AVLNode rightChild;
    336     int val;
    337 
    338     public AVLNode(AVLNode parent, AVLNode leftChild, AVLNode rightChild, int val) {
    339         this.parent = parent;
    340         this.leftChild = leftChild;
    341         this.rightChild = rightChild;
    342         this.val = val;
    343     }
    344 
    345     public AVLNode(int val) {
    346         this.parent = null;
    347         this.leftChild = null;
    348         this.rightChild = null;
    349         this.val = val;
    350     }
    351 
    352 }
  • 相关阅读:
    sql 有条件计数
    easyui combox 手动添加项
    只有设置了 name 属性的表单元素才能在提交表单时传递它们的值
    除湿方法
    android 页面跳转,数据回传
    android studio 乱码
    android studio 工具
    gridlaylout 简单布局
    android 开发 简单的页面布局
    android sdk
  • 原文地址:https://www.cnblogs.com/SamNicole1809/p/12982447.html
Copyright © 2020-2023  润新知