zoukankan      html  css  js  c++  java
  • 05 二分搜索树(BinarySearchTree)

      1 import java.util.LinkedList;
      2 import java.util.Queue;
      3 import java.util.Stack;
      4 
      5 /**
      6  * @author 阿遠
      7  * Date: 2019/4/30
      8  * Time: 15:23
      9  */
     10 public class BinarySearchTree<E extends Comparable<E>> {
     11 
     12     // 内部类定义节点
     13     private class Node{
     14         public E e;  // 节点值
     15         public Node left, right; // 左右节点
     16         // 构造函数
     17         public Node(E e) {
     18             this.e = e;
     19             this.left = null;
     20             this.right = null;
     21         }
     22     }
     23 
     24     private Node root; // 根节点
     25     private int size;  // 深度
     26 
     27     public  BinarySearchTree() {
     28         root = null;
     29         size = 0;
     30     }
     31 
     32     public int size() {
     33         return size;
     34     }
     35 
     36     public boolean isEmpty() {
     37          return size == 0;
     38     }
     39 
     40     // 向二分搜索树中添加新的元素e
     41 //    public void add(E e) {
     42 //        if (root == null) {
     43 //            root = new Node(e);
     44 //            size ++;
     45 //        } else {
     46 //            add(root, e);
     47 //        }
     48 //    }
     49     // 代码优化
     50     public void add(E e) {
     51         root = add(root, e);
     52     }
     53     // 向跟为node的二分搜索树种插入元素E,递归算法
     54 //    private void add(Node node, E e) {
     55 //        // 插入结束的条件
     56 //        if (e.equals(node.e)) { // 插入值与节点值相等
     57 //            return;
     58 //        } else if (e.compareTo(node.e) < 0 && node.left == null) {  // 插入值小于节点并且左子树为空
     59 //            node.left = new Node(e);
     60 //            size ++;
     61 //            return;
     62 //        } else if (e.compareTo(node.e) > 0 && node.right == null) { // 插入值大于节点并且右子树为空
     63 //            node.right = new Node(e);
     64 //            size ++;
     65 //            return;
     66 //        }
     67 //        // 递归插入
     68 //        if(e.compareTo(node.e) < 0) {
     69 //            add(node.left , e);
     70 //        } else {
     71 //            add(node.right, e);
     72 //        }
     73 //    }
     74     // add(Node node, E e) 代码优化: 返回插入新节点后的二分搜索树的根
     75     private Node add(Node node, E e) {
     76         if (node == null) {
     77             size ++;
     78             return new Node(e);
     79         }
     80         if (e.compareTo(node.e) < 0) {
     81             node.left = add(node.left, e);
     82         } else if (e.compareTo(node.e) > 0) {
     83             node.right = add(node.right, e);
     84         }
     85         return node;
     86     }
     87 
     88     // 看二分搜索树中是否包含元素e
     89     public boolean contains(E e) {
     90         return contains(root, e);
     91     }
     92     private boolean contains(Node node, E e) {
     93         if (node == null) {
     94             return false;
     95         }
     96         // 结束条件
     97         if (e.compareTo(node.e) == 0) {
     98             return true;
     99         }else if (e.compareTo(node.e) < 0) {  // 没有结束就递归
    100             return contains(node.left, e);
    101         }else { //e.compareTo(node.e) > 0
    102             return contains(node.right, e);
    103         }
    104     }
    105 
    106     // 寻找二分搜索树的最小值
    107     public E minimum() {
    108         if (size == 0)
    109             throw new IllegalArgumentException("BinarySearchTree is Empty");
    110         return minimum(root).e;
    111     }
    112     private Node minimum(Node node) {
    113         if (node.left == null)
    114             return node;
    115         return minimum(node.left);
    116     }
    117 
    118     // 寻找二分搜索树的最大值
    119     public E maxmum() {
    120         if (size == 0)
    121             throw new IllegalArgumentException("BinarySearchTree is Empty");
    122         return maxmum(root).e;
    123     }
    124     private Node maxmum(Node node) {
    125         if (node.right == null)
    126             return node;
    127         return maxmum(node.right);
    128     }
    129 
    130     // 从二分搜索树中删除最小值所在节点,返回最小值
    131     public E removeMin() {
    132         E ret = minimum();
    133         removeMin(root);
    134         return ret;
    135     }
    136     // 删除掉以node为根的二分搜索树中的最小节点
    137     // 返回删除节点后新的二分搜索树的根
    138     private Node removeMin(Node node)  {
    139         if (node.left == null) {
    140             Node rightNode = node.right;
    141             node.right = null;
    142             size --;
    143             return rightNode;
    144         }
    145         node.left = removeMin(node.left);
    146         return node;
    147     }
    148 
    149     // 从二分搜索树中删除最大值所在节点,返回最大值
    150     public E removeMax() {
    151         E ret = maxmum();
    152         removeMax(root);
    153         return ret;
    154     }
    155     // 删除掉以node为根的二分搜索树中的最小节点
    156     // 返回删除节点后新的二分搜索树的根
    157     private Node removeMax(Node node)  {
    158         if (node.right == null) {
    159             Node leftNode = node.left;
    160             node.left = null;
    161             size --;
    162             return leftNode;
    163         }
    164         node.right = removeMax(node.right);
    165         return node;
    166     }
    167 
    168     // 从二分搜索树中删除元素为e节点
    169     public void remove(E e) {
    170         remove(root, e);
    171     }
    172     private Node remove(Node node, E e) {
    173         if (node == null)  // 如果二分搜索树为空
    174             return null;
    175         if (e.compareTo(node.e) < 0) {
    176             node.left = remove(node.left,e);
    177             return node;
    178         } else if (e.compareTo(node.e) > 0) {
    179             node.right = remove(node.right, e);
    180             return node;
    181         }else {  // e == node.e
    182             // 待删除左子树为空的情况
    183             if (node.left == null) {
    184                 Node rightNode = node.left;
    185                 node.right = null;
    186                 size --;
    187                 return rightNode;
    188             }
    189             // 待删除右子树为空的情况
    190             if (node.right == null) {
    191                 Node leftNode = node.left;
    192                 node.left = null;
    193                 size --;
    194                 return leftNode;
    195             }
    196             // 待删除节点左右子树均不为空的情况
    197             // 找到比待删除节点大的最小节点,即将删除节点右子树的最小节点
    198             // 用这个节点顶替待删除节点的位置
    199             // 该方法的核心代码
    200             Node successor = minimum(node.right);  // 后继
    201             successor.right = removeMax(node.right);  // removeMax的作用是将node.right右子树的最小值删除
    202             successor.left = node.left;
    203             node.left = node.right = null;
    204             return successor;
    205         }
    206     }
    207 
    208     // 二分搜索树递归前序遍历
    209     public void preOrder() {
    210         preOrder(root);
    211     }
    212     private void preOrder(Node node) {
    213         // 递归终止条件
    214         if (node == null) {
    215             return;
    216         }
    217         // 对递归元素进行操作
    218         System.out.println(node.e);
    219         // 没有结束就递归
    220         preOrder(node.left);
    221         preOrder(node.right);
    222     }
    223 
    224     // 二叉搜索树的非递归前序遍历
    225     public void preOrderNR() {
    226 
    227         Stack<Node> stack = new Stack<>();
    228         stack.push(root);
    229         while (!stack.isEmpty()) {
    230             Node cur = stack.pop();
    231             System.out.println(cur.e);
    232             if (cur.right != null) {
    233                 stack.push(cur.right);
    234             }
    235             if (cur.left != null) {
    236                 stack.push(cur.left);
    237             }
    238         }
    239     }
    240 
    241     // 二分搜索树的中序遍历
    242     public void inOrder() {
    243         inOrder(root);
    244     }
    245     // 中序遍历以node为根的二分搜索树,递归算法  二分搜索树的中序遍历就是元素从小到大排序后的结果
    246     private void inOrder(Node node) {
    247         if (node == null) {
    248             return;
    249         }
    250         inOrder(node.left);
    251         System.out.println(node.e);
    252         inOrder(node.right);
    253     }
    254 
    255     // 二分搜索树的后序遍历
    256     public void postOrder() {
    257         postOrder(root);
    258     }
    259     // 后序遍历以node为根的二分搜索树,递归算法
    260     private void postOrder(Node node) {
    261         if (node == null) {
    262             return;
    263         }
    264         postOrder(node.left);
    265         postOrder(node.right);
    266         System.out.println(node.e);
    267     }
    268 
    269     // 前面实现的前中后三种遍历本质上都是深度优先的遍历,下面介绍层序遍历,以层为优先的遍历
    270     // 层序遍历:一层一层的遍历
    271     public void levelOrder() {
    272         Queue<Node> q = new LinkedList<>();  // Queue在java中是一个借口,需使用具体的类(LinkedList)进行实现
    273         q.add(root);
    274         while (!q.isEmpty()) {
    275             Node cur = q.remove();
    276             System.out.println(cur.e);
    277 
    278             if (cur.left != null)
    279                 q.add(cur.left);
    280             if (cur.right != null)
    281                 q.add(cur.right);
    282         }
    283     }
    284 
    285     @Override
    286     public String toString() {
    287         StringBuilder res = new StringBuilder();
    288         generateBSTString(root, 0, res);
    289         return res.toString();
    290     }
    291     // 生成以node为根节点,深度为depth的描述二叉树的字符串
    292     private void generateBSTString(Node node, int depth, StringBuilder res) {
    293         if (node == null) {
    294             res.append(generateDepthString(depth) + node.e + "null
    ");
    295             return;
    296         }
    297         res.append(generateDepthString(depth) + node.e + "null
    ");
    298         generateBSTString(node.left, depth + 1, res);
    299         generateBSTString(node.right, depth + 1, res);
    300     }
    301 
    302     private String generateDepthString(int depth) {
    303         StringBuilder res = new StringBuilder();
    304         for (int i = 0; i < depth; i ++) {
    305             res.append("--");
    306         }
    307         return res.toString();
    308     }
    309 }
  • 相关阅读:
    理解和应用队列机制
    Visual Studio for Mac第四预
    宇宙第一开发工具
    Visual Studio 2017
    Vue开源
    Redux 和 ngrx 创建更佳的 Angular 2
    Redis缓存用起来
    C#6
    spring声明式事务 同一类内方法调用事务失效
    Spring事务管理--多个ORM框架在使用时的情况分析
  • 原文地址:https://www.cnblogs.com/a-yuan/p/10800586.html
Copyright © 2011-2022 走看看