• 数据结构-平衡二叉树Java实现


    1,Node.java

     1 package com.cnblogs.mufasa.BalanceBinaryTree;
     2 
     3 public class Node {
     4     Node parent;
     5     Node leftChild;
     6     Node rightChild;
     7     int val;
     8     public Node(Node parent, Node leftChild, Node rightChild,int val) {
     9         super();
    10         this.parent = parent;
    11         this.leftChild = leftChild;
    12         this.rightChild = rightChild;
    13         this.val = val;
    14     }
    15 
    16     public Node(int val){
    17         this(null,null,null,val);
    18     }
    19 
    20     public Node(Node node,int val){
    21         this(node,null,null,val);
    22     }
    23 }
    View Code

     

    图1 Node.java结构图

    2,BalanceBinaryTree.java

      1 package com.cnblogs.mufasa.BalanceBinaryTree;
      2 
      3 import java.util.LinkedList;
      4 import java.util.Queue;
      5 
      6 public class BalanceBinaryTree {
      7     private final static int LEFT=0;
      8     private final static int RIGHT=1;
      9     private Node root;
     10     private int size;
     11     public BalanceBinaryTree(){
     12         super();
     13     }
     14 
     15     //LL型非平衡树,右旋转
     16     public Node rightRotation(Node node){
     17         System.out.println(node.val+"右旋");
     18         if(node != null){
     19             Node leftChild = node.leftChild;// 用变量存储node节点的左子节点
     20             node.leftChild = leftChild.rightChild;// 将leftChild节点的右子节点赋值给node节点的左节点
     21             if(leftChild.rightChild != null){// 如果leftChild的右节点存在,则需将该右节点的父节点指给node节点
     22                 leftChild.rightChild.parent = node;
     23             }
     24             leftChild.parent = node.parent;
     25             if(node.parent == null){// 即表明node节点为根节点
     26                 this.root = leftChild;
     27             }else if(node.parent.rightChild == node){// 即node节点在它原父节点的右子树中
     28                 node.parent.rightChild = leftChild;
     29             }else if(node.parent.leftChild == node){
     30                 node.parent.leftChild = leftChild;
     31             }
     32             leftChild.rightChild = node;
     33             node.parent = leftChild;
     34             return leftChild;
     35         }
     36         return null;
     37     }
     38 
     39     //RR型非平衡树,左旋
     40     public Node leftRotation(Node node){
     41         System.out.println(node.val+"左旋");
     42         if(node != null){
     43             Node rightChild = node.rightChild;
     44             node.rightChild = rightChild.leftChild;
     45             if(rightChild.leftChild != null){
     46                 rightChild.leftChild.parent = node;
     47             }
     48             rightChild.parent = node.parent;
     49             if(node.parent == null){
     50                 this.root = rightChild;
     51             }else if(node.parent.rightChild == node){
     52                 node.parent.rightChild = rightChild;
     53             }else if(node.parent.leftChild == node){
     54                 node.parent.leftChild = rightChild;
     55             }
     56             rightChild.leftChild = node;
     57             node.parent = rightChild;
     58 
     59         }
     60         return null;
     61     }
     62 
     63     //添加新元素
     64     public boolean put(int val){
     65         return putVal(root,val);
     66     }
     67     private boolean putVal(Node node,int val){
     68         if(node == null){// 初始化根节点
     69             node = new Node(val);
     70             root = node;
     71             size++;
     72             return true;
     73         }
     74         Node temp = node;
     75         Node p;
     76         int t;
     77         /**
     78          * 通过do while循环迭代获取最佳节点,
     79          */
     80         do{
     81             p = temp;
     82             t = temp.val-val;
     83             if(t > 0){
     84                 temp = temp.leftChild;
     85             }else if(t < 0){
     86                 temp = temp.rightChild;
     87             }else{
     88                 temp.val = val;//插入数值有相同数据,不符合要求
     89                 return false;
     90             }
     91         }while(temp != null);
     92 
     93         Node newNode = new Node(p, val);
     94         if(t > 0){
     95             p.leftChild = newNode;
     96         }else if(t < 0){
     97             p.rightChild = newNode;
     98         }
     99         rebuild(p);// 使二叉树平衡的方法,优化平衡
    100         size++;
    101         return true;
    102     }
    103 
    104     //平衡二叉树优化节点
    105     private void rebuild(Node p){
    106         while(p != null){
    107             if(calcNodeBalanceValue(p) == 2){// 说明左子树高,需要右旋或者 先左旋后右旋
    108                 fixAfterInsertion(p,LEFT);// 调整操作
    109             }else if(calcNodeBalanceValue(p) == -2){// 说明右子树高
    110                 fixAfterInsertion(p,RIGHT);
    111             }
    112             p = p.parent;
    113         }
    114     }
    115 
    116     //计算二叉树平衡因子①
    117     private int calcNodeBalanceValue(Node node){
    118         if(node != null){
    119             return getHeightByNode(node);
    120         }
    121         return 0;
    122     }
    123 
    124     //计算二叉树平衡因子②
    125     public int getHeightByNode(Node node){
    126         if(node == null){//多余
    127             return 0;
    128         }
    129         return getChildDepth(node.leftChild)-getChildDepth(node.rightChild);
    130     }
    131 
    132     // 计算node节点的高度,递归调用
    133     public int getChildDepth(Node node){
    134         if(node == null){
    135             return 0;
    136         }
    137         return 1+Math.max(getChildDepth(node.leftChild),getChildDepth(node.rightChild));
    138     }
    139 
    140     /**
    141      * 调整树结构,先后顺序需要换一下,先判断LR型和RL型进行二次旋转
    142      * @param p
    143      * @param type
    144      */
    145     private void fixAfterInsertion(Node p, int type) {
    146         if(type == 0){//需要右旋或者 先左旋后右旋
    147             final Node leftChild = p.leftChild;
    148             if(leftChild.rightChild != null){// 先左旋后右旋
    149                 leftRotation(leftChild);
    150                 rightRotation(p);
    151             }else if(leftChild.leftChild != null){//右旋
    152                 rightRotation(p);
    153             }
    154 
    155         }else{
    156             final Node rightChild = p.rightChild;
    157             if(rightChild.leftChild != null){// 先右旋,后左旋
    158                 rightRotation(p);
    159                 leftRotation(rightChild);
    160             }else if(rightChild.rightChild != null){// 左旋
    161                 leftRotation(p);
    162             }
    163         }
    164     }
    165 
    166     //删除元素
    167     public boolean delete(int val){
    168         Node node = getNode(val);//搜索这个节点的数值
    169         if(node == null){
    170             return false;
    171         }
    172         boolean flag = false;
    173         Node p = null;
    174         Node parent = node.parent;
    175         Node leftChild = node.leftChild;
    176         Node rightChild = node.rightChild;
    177         //以下所有父节点为空的情况,则表明删除的节点是根节点
    178         if(leftChild == null && rightChild == null){//没有子节点
    179             if(parent != null){
    180                 if(parent.leftChild == node){
    181                     parent.leftChild = null;
    182                 }else if(parent.rightChild == node){
    183                     parent.rightChild = null;
    184                 }
    185             }else{//不存在父节点,则表明删除节点为根节点
    186                 root = null;
    187             }
    188             p = parent;
    189             node = null;
    190             flag =  true;
    191         }else if(leftChild == null && rightChild != null){// 只有右节点
    192             if(parent != null && parent.val > val){// 存在父节点,且node位置为父节点的左边
    193                 parent.leftChild = rightChild;
    194             }else if(parent != null && parent.val < val){// 存在父节点,且node位置为父节点的右边
    195                 parent.rightChild = rightChild;
    196             }else{
    197                 root = rightChild;
    198             }
    199             p = parent;
    200             node = null;
    201             flag =  true;
    202         }else if(leftChild != null && rightChild == null){// 只有左节点
    203             if(parent != null && parent.val > val){// 存在父节点,且node位置为父节点的左边
    204                 parent.leftChild = leftChild;
    205             }else if(parent != null && parent.val < val){// 存在父节点,且node位置为父节点的右边
    206                 parent.rightChild = leftChild;
    207             }else{
    208                 root = leftChild;
    209             }
    210             p = parent;
    211             flag =  true;
    212         }else if(leftChild != null && rightChild != null){// 两个子节点都存在
    213             Node successor = getSuccessor(node);// 这种情况,一定存在后继节点
    214             int temp = successor.val;
    215             boolean delete = delete(temp);
    216             if(delete){
    217                 node.val = temp;
    218             }
    219             p = successor;
    220             successor = null;
    221             flag =  true;
    222         }
    223         if(flag){
    224             rebuild(p);
    225         }
    226         return flag;
    227     }
    228 
    229     /**
    230      * 搜索节点
    231      * @param val
    232      * @return
    233      */
    234     public Node getNode(int val){
    235         Node temp = root;
    236         int t;
    237         do{//直接使用循环遍历的方法
    238             t = temp.val-val;
    239             if(t > 0){
    240                 temp = temp.leftChild;
    241             }else if(t < 0){
    242                 temp = temp.rightChild;
    243             }else{
    244                 return temp;
    245             }
    246         }while(temp != null);
    247         return null;
    248     }
    249 
    250     //获取后继节点
    251     private Node getSuccessor(Node node){
    252         if(node.rightChild != null){
    253             Node rightChild = node.rightChild;
    254             while(rightChild.leftChild != null){
    255                 rightChild = rightChild.leftChild;
    256             }
    257             return rightChild;
    258         }
    259         Node parent = node.parent;
    260         while(parent != null && (node == parent.rightChild)){
    261             node = parent;
    262             parent = parent.parent;
    263         }
    264         return parent;
    265     }
    266 
    267     /**
    268      * 平衡二叉树节点遍历
    269      * @param type  0前序,1中序,2后续,3层序
    270      */
    271     public void print(int type){
    272         if(type==0){//前序
    273             printPre(root);
    274         }else if(type==1){
    275             printMid(root);
    276         }else if(type==2){
    277             printEnd(root);
    278         }else if(type==3){
    279             printLevel(root);
    280         }
    281     }
    282 
    283     //前序遍历
    284     private void printPre(Node root){
    285         if(root != null){
    286             System.out.println(root.val);// 位置在中间,则中序,若在前面,则为先序,否则为后续
    287             printPre(root.leftChild);
    288             printPre(root.rightChild);
    289         }
    290     }
    291 
    292     //中序遍历
    293     private void printMid(Node root){
    294         if(root != null){
    295             printMid(root.leftChild);
    296             System.out.println(root.val);// 位置在中间,则中序,若在前面,则为先序,否则为后续
    297             printMid(root.rightChild);
    298         }
    299     }
    300 
    301     //后序遍历
    302     private void printEnd(Node root){
    303         if(root != null){
    304             printEnd(root.leftChild);
    305             printEnd(root.rightChild);
    306             System.out.println(root.val);// 位置在中间,则中序,若在前面,则为先序,否则为后续
    307         }
    308     }
    309 
    310     //层次遍历
    311     private void printLevel(Node root){
    312         if(root == null){
    313             return;
    314         }
    315         Queue<Node> queue = new LinkedList<>();
    316         Node temp = null;
    317         queue.add(root);
    318         while(!queue.isEmpty()){
    319             temp = queue.poll();
    320             System.out.print("节点值:"+temp.val+",平衡值:"+calcNodeBalanceValue(temp)+"
    ");
    321             if(temp.leftChild != null){
    322                 queue.add(temp.leftChild);
    323             }
    324             if(temp.rightChild != null){
    325                 queue.add(temp.rightChild);
    326             }
    327         }
    328     }
    329 }
    View Code

    图2,BalanceBinaryTree.java结构图

    3,JavaDemo.java

     1 package com.cnblogs.mufasa.BalanceBinaryTree;
     2 
     3 public class JavaDemo {
     4     public static void main(String[] args) {
     5         BalanceBinaryTree bbt=new BalanceBinaryTree();
     6 //        bbt.put(10);
     7 //        bbt.put(9);
     8 //        bbt.put(11);
     9 //        bbt.put(7);
    10 //        bbt.put(12);
    11 //        bbt.put(8);
    12 //        bbt.put(38);
    13 //        bbt.put(24);
    14 //        bbt.put(17);
    15 //        bbt.put(4);
    16 //        bbt.put(3);
    17 
    18         bbt.put(11);
    19         bbt.put(7);
    20         bbt.put(15);
    21         bbt.put(4);
    22         bbt.put(9);
    23         bbt.put(10);
    24         bbt.print(3);
    25     }
    26 }
    View Code

    4,特别鸣谢

    https://www.cnblogs.com/qm-article/p/9349681.html

  • 相关阅读:
    pytorch 深度学习之数据操作
    pytorch 深度学习之微积分
    pytorch 深度学习之线性代数
    pytorch 深度学习之自动微分
    [Photoshop] ps中选区新建为图层的快捷键
    [Golang] Goland 编辑器 替换快捷键
    Go 自定义 Json 序列化规则
    MySQL入门篇(六)之mysqldump备份和恢复
    go panic 和 recover(重要)
    如何在 Linux 上模拟和缓解 DDoS 攻
  • 原文地址:https://www.cnblogs.com/Mufasa/p/11294145.html
Copyright © 2020-2023  润新知