 
  
【从蛋壳到满天飞】JAVA 数据结构解析和算法实现,全部文章大概的内容如下:
Arrays(数组)、Stacks(栈)、Queues(队列)、LinkedList(链表)、Recursion(递归思想)、BinarySearchTree(二分搜索树)、Set(集合)、Map(映射)、Heap(堆)、PriorityQueue(优先队列)、SegmentTree(线段树)、Trie(字典树)、UnionFind(并查集)、AVLTree(AVL 平衡树)、RedBlackTree(红黑平衡树)、HashTable(哈希表)
源代码有三个:ES6(单个单个的 class 类型的 js 文件) | JS + HTML(一个 js 配合一个 html)| JAVA (一个一个的工程)
全部源代码已上传 github, 点击我吧 ,光看文章能够掌握两成,动手敲代码、动脑思考、画图才可以掌握八成。
本文章适合 对数据结构想了解并且感兴趣的人群,文章风格一如既往如此,就觉得手机上看起来比较方便,这样显得比较有条理,整理这些笔记加源码,时间跨度也算将近半年时间了,希望对想学习数据结构的人或者正在学习数据结构的人群有帮助。
线性数据结构是把所有的数据排成一排
树结构本身是一个种天然的组织结构
树结构非常的高效
在计算机科学领域很多问题的处理
二分搜索树(Binary Search Tree)
平衡二叉树:AVL;红黑树,
算法需要使用一些特殊的操作的时候将数据组织成树结构
堆 以及 并查集 , 线段树、Trie(字典树、前缀树)
二叉树
class Node {
      E e;
      Node left;
      Node right;
   } 二叉树也叫多叉树,
在数据结构领域对应树结构来说
二叉树和链表一样具有天然递归的结构
二叉树不一定是“满”的
二分搜索树是一棵二叉树
二分搜索树的每一个节点的值
二分搜索树的每一棵子树也是二分搜索树
为了能够达到二分搜索树的性质
二分搜索树其实不是支持所有的类型
代码实现
public class MyBinarySearchTree<E extends Comparable<E>> {
         private class Node {
             public E e;
             public Node left, right;
             public Node (E e) {
                   this.e = e;
                   left = null;
                   right = null;
             }
         }
         private Node root;
         private int size;
         public MyBinarySearchTree () {
               root = null;
               size = 0;
         }
         public int getSize() {
               return size;
         }
         public boolean isEmpty () {
               return size == 0;
         }
   } 如果二分搜索树的根节点为空的话
按照这样的规则,每来一个新元素从根节点开始,
如果遇到两个元素的值相同,那暂时先不去管,
二分搜索树添加元素的非递归写法,和链表很像
代码
public class MyBinarySearchTree<E extends Comparable<E>> {
         private class Node {
             public E e;
             public Node left, right;
             public Node (E e) {
                   this.e = e;
                   left = null;
                   right = null;
             }
         }
         private Node root;
         private int size;
         public MyBinarySearchTree () {
               root = null;
               size = 0;
         }
         public int getSize() {
               return size;
         }
         public boolean isEmpty () {
               return size == 0;
         }
         // 向二分搜索树中添加一个元素 e
         public void add (E e) {
               if (root == null) {
                     root = new Node(e);
                     size ++;
               } else {
                     add(root, e);
               }
         }
         // 向以node为根的二分搜索树种插入元素E,递归算法
         private void add (Node node, E e) {
               // node 是对用户屏蔽的,用户不用知道二分搜索树中有怎样一个节点结构
               // 如果出现相同的元素就不进行操作了
               if (e.equals(node.e)) {
                     return;
               } else if (e.compareTo(node.e) < 0 && node.left == null) {
                     // 给左孩子赋值
                     node.left = new Node(e);
                     size ++;
                     return;
               } else if (e.compareTo(node.e) > 0 && node.right == null) {
                     // 给右海子赋值
                     node.right = new Node(e);
                     size ++;
                     return;
               }
               // 这里是处理节点被占了,那就进入下一个层的二叉树中
               if (e.compareTo(node.e) < 0) {
                     // 去左子树
                     add(node.left, e);
               } else { // e.compareTo(node.e) > 0
                     // 去右子树
                     add(node.right, e);
               }
         }
   } 对于二分搜索的插入操作
改进添加操作
之前的算法
代码
public class MyBinarySearchTree<E extends Comparable<E>> {
         private class Node {
             public E e;
             public Node left, right;
             public Node (E e) {
                   this.e = e;
                   left = null;
                   right = null;
             }
         }
         private Node root;
         private int size;
         public MyBinarySearchTree () {
               root = null;
               size = 0;
         }
         public int getSize() {
               return size;
         }
         public boolean isEmpty () {
               return size == 0;
         }
         // 向二分搜索树中添加一个元素 e
         // 改进:直接调用add
         public void add (E e) {
               root = add(root, e);
         }
         // 向以node为根的二分搜索树种插入元素E,递归算法
         // 改进:返回插入的新节点后二分搜索树的根
         private Node add (Node node, E e) {
               // 处理最基本的问题
               if (node == null) {
                     size ++;
                     return new Node(e);
               }
               // 空的二叉树也是叉树。
               if (e.compareTo(node.e) < 0) {
                     // 将处理后的结果赋值给node的左子树
                     node.left =  add(node.left, e);
               } else if (e.compareTo(node.e) > 0) {
                     // 将处理后的结果赋值给node的右子树
                     node.right =  add(node.right, e);
               } // 如果相同 就什么都不做
               // 最后返回这个node
               return node;
         }
   //    // 向二分搜索树中添加一个元素 e
   //    public void add (E e) {
   //        if (root == null) {
   //            root = new Node(e);
   //            size ++;
   //        } else {
   //            add(root, e);
   //        }
   //    }
   //    // 向以node为根的二分搜索树种插入元素E,递归算法
   //    private void add (Node node, E e) {
   //        // node 是对用户屏蔽的,用户不用知道二分搜索树中有怎样一个节点结构
   //
   //        // 如果出现相同的元素就不进行操作了
   //        if (e.equals(node.e)) {
   //            return;
   //        } else if (e.compareTo(node.e) < 0 && node.left == null) {
   //            // 给左孩子赋值
   //            node.left = new Node(e);
   //            return;
   //        } else if (e.compareTo(node.e) > 0 && node.right == null) {
   //            // 给右海子赋值
   //            node.right = new Node(e);
   //            return;
   //        }
   //
   //        // 这里是处理节点被占了,那就进入下一个层的二叉树中
   //        if (e.compareTo(node.e) < 0) {
   //            // 去左子树
   //            add(node.left, e);
   //        } else { // e.compareTo(node.e) > 0
   //            // 去右子树
   //            add(node.right, e);
   //        }
   //    }
   } 虽然代码量更少了,但是也更难理解的了一些
查询操作非常的容易
和添加元素一样需要使用递归的进行实现
在数组和链表中有索引这个概念,
代码
public class MyBinarySearchTree<E extends Comparable<E>> {
         private class Node {
             public E e;
             public Node left, right;
             public Node (E e) {
                   this.e = e;
                   left = null;
                   right = null;
             }
         }
         private Node root;
         private int size;
         public MyBinarySearchTree () {
               root = null;
               size = 0;
         }
         public int getSize() {
               return size;
         }
         public boolean isEmpty () {
               return size == 0;
         }
         // 向二分搜索树中添加一个元素 e
         // 改进:直接调用add
         public void add (E e) {
               root = add(root, e);
         }
         // 向以node为根的二分搜索树中插入元素E,递归算法
         // 改进:返回插入的新节点后二分搜索树的根
         private Node add (Node node, E e) {
               // 处理最基本的问题
               if (node == null) {
                     size ++;
                     return new Node(e);
               }
               // 空的二叉树也是叉树。
               if (e.compareTo(node.e) < 0) {
                     // 将处理后的结果赋值给node的左子树
                     node.left =  add(node.left, e);
               } else if (e.compareTo(node.e) > 0) {
                     // 将处理后的结果赋值给node的右子树
                     node.right =  add(node.right, e);
               } // 如果相同 就什么都不做
               // 最后返回这个node
               return node;
         }
         // 查询二分搜索数中是否包含某个元素
         public boolean contains (E e) {
               return contains(root, e);
         }
         // 向以node为根的二分搜索树 进行查找  递归算法
         public boolean contains (Node node, E e) {
               // 解决最基本的问题 也就是遍历完所有节点都没有找到
               if (node == null) {
                     return false;
               }
               // 如果 e 小于当前节点的e 则向左子树进发
               if (e.compareTo(node.e) < 0) {
                   return contains(node.left, e);
               } else if (e.compareTo(node.e) > 0) { // 如果 e 大于当前节点的e 则向右子树进发
                   return contains(node.right, e);
               } else { // 如果e 等于 当前节点 e 则直接返回true
                     return true;
               }
         }
   } 遍历操作就是把这个数据结构中所有的元素都访问一遍
访问数据结构中存储的所有元素是因为与业务相关,
在线性结构下,遍历是极其容易的
在树结构下遍历操作并没有那么难
对于遍历操作,两个子树都要顾及
// 遍历以node为根的二分搜索树 递归算法
function traverse(node) {
   if (node === null) {
      return;
   }
   // ... 要做的事情
   // 访问该节点 两边都要顾及
   // 访问该节点的时候就去做该做的事情,
   // 如 给所有学生加两分
   traverse(node.left);
   traverse(node.right);
}
// 写法二 这种逻辑也是可以的
function traverse(node) {
   if (node !== null) {
      // ... 要做的事情
      // 访问该节点 两边都要顾及
      // 访问该节点的时候就去做该做的事情,
      // 如 给所有学生加两分
      traverse(node.left);
      traverse(node.right);
   }
} (class: MyBinarySearchTree, class: Main) MyBinarySearchTree
public class MyBinarySearchTree<E extends Comparable<E>> {
         private class Node {
             public E e;
             public Node left, right;
             public Node (E e) {
                   this.e = e;
                   left = null;
                   right = null;
             }
         }
         private Node root;
         private int size;
         public MyBinarySearchTree () {
               root = null;
               size = 0;
         }
         public int getSize() {
               return size;
         }
         public boolean isEmpty () {
               return size == 0;
         }
         // 向二分搜索树中添加一个元素 e
         // 改进:直接调用add
         public void add (E e) {
               root = add(root, e);
         }
         // 向以node为根的二分搜索树中插入元素E,递归算法
         // 改进:返回插入的新节点后二分搜索树的根
         private Node add (Node node, E e) {
               // 处理最基本的问题
               if (node == null) {
                     size ++;
                     return new Node(e);
               }
               // 空的二叉树也是叉树。
               if (e.compareTo(node.e) < 0) {
                     // 将处理后的结果赋值给node的左子树
                     node.left =  add(node.left, e);
               } else if (e.compareTo(node.e) > 0) {
                     // 将处理后的结果赋值给node的右子树
                     node.right =  add(node.right, e);
               } // 如果相同 就什么都不做
               // 最后返回这个node
               return node;
         }
         // 查询二分搜索数中是否包含某个元素
         public boolean contains (E e) {
               return contains(root, e);
         }
         // 向以node为根的二分搜索树 进行查找  递归算法
         public boolean contains (Node node, E e) {
               // 解决最基本的问题 也就是遍历完所有节点都没有找到
               if (node == null) {
                     return false;
               }
               // 如果 e 小于当前节点的e 则向左子树进发
               if (e.compareTo(node.e) < 0) {
                   return contains(node.left, e);
               } else if (e.compareTo(node.e) > 0) { // 如果 e 大于当前节点的e 则向右子树进发
                   return contains(node.right, e);
               } else { // 如果e 等于 当前节点 e 则直接返回true
                     return true;
               }
         }
         // 二分搜索树的前序遍历
         public void preOrder () {
               preOrder(root);
         }
         // 前序遍历以node为根的二分搜索树 递归算法
         public void preOrder (Node node) {
               if (node == null) {
                     return;
               }
               // 输出
               System.out.println(node.e);
               preOrder(node.left);
               preOrder(node.right);
   //        // 这种逻辑也是可以的
   //        if (node != null) {
   //            // 输出
   //            System.out.println(node.e);
   //
   //            preOrder(node.left);
   //            preOrder(node.right);
   //        }
         }
   } Main
public class Main {
         public static void main(String[] args) {
               MyBinarySearchTree<Integer> mbst = new MyBinarySearchTree<Integer>();
               int [] nums = {5, 3, 6, 8, 4, 2};
               for (int i = 0; i < nums.length ; i++) {
                     mbst.add(nums[i]);
               }
               /////////////////
               //      5      //
               //    /   /    //
               //   3    6    //
               //  / /    /   //
               // 2  4     8  //
               /////////////////
               mbst.preOrder();
         }
   } 遍历输出二分搜索树
(class: MyBinarySearchTree, class: Main) MyBinarySearchTree
public class MyBinarySearchTree<E extends Comparable<E>> {
         private class Node {
             public E e;
             public Node left, right;
             public Node (E e) {
                   this.e = e;
                   left = null;
                   right = null;
             }
         }
         private Node root;
         private int size;
         public MyBinarySearchTree () {
               root = null;
               size = 0;
         }
         public int getSize() {
               return size;
         }
         public boolean isEmpty () {
               return size == 0;
         }
         // 向二分搜索树中添加一个元素 e
         // 改进:直接调用add
         public void add (E e) {
               root = add(root, e);
         }
         // 向以node为根的二分搜索树中插入元素E,递归算法
         // 改进:返回插入的新节点后二分搜索树的根
         private Node add (Node node, E e) {
               // 处理最基本的问题
               if (node == null) {
                     size ++;
                     return new Node(e);
               }
               // 空的二叉树也是叉树。
               if (e.compareTo(node.e) < 0) {
                     // 将处理后的结果赋值给node的左子树
                     node.left =  add(node.left, e);
               } else if (e.compareTo(node.e) > 0) {
                     // 将处理后的结果赋值给node的右子树
                     node.right =  add(node.right, e);
               } // 如果相同 就什么都不做
               // 最后返回这个node
               return node;
         }
         // 查询二分搜索数中是否包含某个元素
         public boolean contains (E e) {
               return contains(root, e);
         }
         // 向以node为根的二分搜索树 进行查找  递归算法
         public boolean contains (Node node, E e) {
               // 解决最基本的问题 也就是遍历完所有节点都没有找到
               if (node == null) {
                     return false;
               }
               // 如果 e 小于当前节点的e 则向左子树进发
               if (e.compareTo(node.e) < 0) {
                   return contains(node.left, e);
               } else if (e.compareTo(node.e) > 0) { // 如果 e 大于当前节点的e 则向右子树进发
                   return contains(node.right, e);
               } else { // 如果e 等于 当前节点 e 则直接返回true
                     return true;
               }
         }
         // 二分搜索树的前序遍历
         public void preOrder () {
               preOrder(root);
         }
         // 前序遍历以node为根的二分搜索树 递归算法
         public void preOrder (Node node) {
               if (node == null) {
                     return;
               }
               // 输出
               System.out.println(node.e);
               preOrder(node.left);
               preOrder(node.right);
   //        // 这种逻辑也是可以的
   //        if (node != null) {
   //            // 输出
   //            System.out.println(node.e);
   //
   //            preOrder(node.left);
   //            preOrder(node.right);
   //        }
         }
         @Override
         public String toString () {
               StringBuilder sb = new StringBuilder();
               generateBSTString(root, 0, sb);
               return sb.toString();
         }
         // 生成以node为根节点,深度为depth的描述二叉树的字符串
         private void generateBSTString (Node node, int depath, StringBuilder sb) {
               if (node == null) {
                     sb.append(generateDepthString(depath) + "null/n");
                     return;
               }
               sb.append(generateDepthString(depath) + node.e + "/n");
               generateBSTString(node.left, depath + 1, sb);
               generateBSTString(node.right, depath + 1, sb);
         }
         // 生成路径字符串
         private String generateDepthString (int depth) {
               StringBuilder sb = new StringBuilder();
               for (int i = 0; i < depth; i++) {
                     sb.append("-- ");
               }
               return  sb.toString();
         }
   } Main
public class Main {
         public static void main(String[] args) {
               MyBinarySearchTree<Integer> mbst = new MyBinarySearchTree<Integer>();
               int [] nums = {5, 3, 6, 8, 4, 2};
               for (int i = 0; i < nums.length ; i++) {
                     mbst.add(nums[i]);
               }
               /////////////////
               //      5      //
               //    /   /    //
               //   3    6    //
               //  / /    /   //
               // 2  4     8  //
               /////////////////
               mbst.preOrder();
               System.out.println();
               // 输出 调试字符串
               System.out.println(mbst.toString());
         }
   } 前序遍历
前
function preOrder(node) {
   if (node == null) return;
   // ... 要做的事情
   // 访问该节点
   // 先一直往左,然后不断返回上一层 再向左、终止,
   // 最后整个操作循环往复,直到全部终止。
   preOrder(node.left);
   preOrder(node.right);
} 中序遍历
中
function inOrder(node) {
   if (node == null) return;
   inOrder(node.left);
   // ... 要做的事情
   // 访问该节点
   inOrder(node.right);
} 中序遍历后输出的结果是排序后的结果。
后序遍历
后
function inOrder(node) {
   if (node == null) return;
   inOrder(node.left);
   inOrder(node.right);
   // ... 要做的事情
   // 访问该节点
} 二分搜索树的前序遍历和后序遍历并不像中序遍历那样进行了排序
java 、 c# 这样的语言都有垃圾回收机制, c++ 语言中需要手动的控制内存, 二分搜索树的前中后序遍历
(class: MyBinarySearchTree, class: Main) MyBinarySearchTree
public class MyBinarySearchTree<E extends Comparable<E>> {
         private class Node {
             public E e;
             public Node left, right;
             public Node (E e) {
                   this.e = e;
                   left = null;
                   right = null;
             }
         }
         private Node root;
         private int size;
         public MyBinarySearchTree () {
               root = null;
               size = 0;
         }
         public int getSize() {
               return size;
         }
         public boolean isEmpty () {
               return size == 0;
         }
         // 向二分搜索树中添加一个元素 e
         // 改进:直接调用add
         public void add (E e) {
               root = add(root, e);
         }
         // 向以node为根的二分搜索树中插入元素E,递归算法
         // 改进:返回插入的新节点后二分搜索树的根
         private Node add (Node node, E e) {
               // 处理最基本的问题
               if (node == null) {
                     size ++;
                     return new Node(e);
               }
               // 空的二叉树也是叉树。
               if (e.compareTo(node.e) < 0) {
                     // 将处理后的结果赋值给node的左子树
                     node.left =  add(node.left, e);
               } else if (e.compareTo(node.e) > 0) {
                     // 将处理后的结果赋值给node的右子树
                     node.right =  add(node.right, e);
               } // 如果相同 就什么都不做
               // 最后返回这个node
               return node;
         }
         // 查询二分搜索数中是否包含某个元素
         public boolean contains (E e) {
               return contains(root, e);
         }
         // 向以node为根的二分搜索树 进行查找  递归算法
         private boolean contains (Node node, E e) {
               // 解决最基本的问题 也就是遍历完所有节点都没有找到
               if (node == null) {
                     return false;
               }
               // 如果 e 小于当前节点的e 则向左子树进发
               if (e.compareTo(node.e) < 0) {
                   return contains(node.left, e);
               } else if (e.compareTo(node.e) > 0) { // 如果 e 大于当前节点的e 则向右子树进发
                   return contains(node.right, e);
               } else { // 如果e 等于 当前节点 e 则直接返回true
                     return true;
               }
         }
         // 二分搜索树的前序遍历
         public void preOrder () {
               preOrder(root);
         }
         // 前序遍历以node为根的二分搜索树 递归算法
         private void preOrder (Node node) {
               if (node == null) {
                     return;
               }
               // 输出
               System.out.println(node.e);
               preOrder(node.left);
               preOrder(node.right);
   //        // 这种逻辑也是可以的
   //        if (node != null) {
   //            // 输出
   //            System.out.println(node.e);
   //
   //            preOrder(node.left);
   //            preOrder(node.right);
   //        }
         }
         // 二分搜索树的中序遍历
         public void inOrder () {
               inOrder(root);
         }
         // 中序遍历以node为根的二分搜索树 递归算法
         private void inOrder (Node node) {
               if (node == null) return;
               inOrder(node.left);
               System.out.println(node.e);
               inOrder(node.right);
         }
         // 二分搜索树的后序遍历
         public void postOrder () {
               postOrder(root);
         }
         // 后续遍历以node为根的二分搜索树 递归算法
         private void postOrder (Node node) {
               if (node == null) return;
               postOrder(node.left);
               postOrder(node.right);
               System.out.println(node.e);
         }
         @Override
         public String toString () {
               StringBuilder sb = new StringBuilder();
               generateBSTString(root, 0, sb);
               return sb.toString();
         }
         // 生成以node为根节点,深度为depth的描述二叉树的字符串
         private void generateBSTString (Node node, int depath, StringBuilder sb) {
               if (node == null) {
                     sb.append(generateDepthString(depath) + "null/n");
                     return;
               }
               sb.append(generateDepthString(depath) + node.e + "/n");
               generateBSTString(node.left, depath + 1, sb);
               generateBSTString(node.right, depath + 1, sb);
         }
         // 生成路径字符串
         private String generateDepthString (int depth) {
               StringBuilder sb = new StringBuilder();
               for (int i = 0; i < depth; i++) {
                     sb.append("-- ");
               }
               return  sb.toString();
         }
   } Main
public class Main {
         public static void main(String[] args) {
               MyBinarySearchTree<Integer> mbst = new MyBinarySearchTree<Integer>();
               int [] nums = {5, 3, 6, 8, 4, 2};
               for (int i = 0; i < nums.length ; i++) {
                     mbst.add(nums[i]);
               }
               /////////////////
               //      5      //
               //    /   /    //
               //   3    6    //
               //  / /    /   //
               // 2  4     8  //
               /////////////////
               // 前序遍历
               mbst.preOrder(); // 5 3 2 4 6 8
               System.out.println();
               // 中序遍历
               mbst.inOrder(); // 2 3 4 5 6 8
               System.out.println();
               // 后序遍历
               mbst.postOrder(); // 2 4 3 8 6 5
               System.out.println();
   //        // 输出 调试字符串
   //        System.out.println(mbst.toString());
         }
   } 再看二分搜索树的遍历
对二分搜索树前中后这三种顺序的遍历
function traverse(node) {
   if (node === null) return;
   // 1. 第一个访问的机会   前
   traverse(node.left);
   // 2. 第二个访问的机会   中
   traverse(node.right);
   // 3. 第三个访问的机会   后
} 二叉树前中后序遍历访问节点的不同
前序遍历的递归写法
前
function preOrder(node) {
   if (node == null) return;
   // ... 要做的事情
   // 访问该节点
   // 先一直往左,然后不断返回上一层 再向左、终止,
   // 最后整个操作循环往复,直到全部终止。
   preOrder(node.left);
   preOrder(node.right);
} 前序遍历的非递归写法
栈
无论是非递归还是递归的写法,结果都是一致的
将递归算法转换为非递归算法
二分搜索树遍历的非递归实现比递归实现复杂很多
二分搜索树的中序遍历和后序遍历的非递归实现更复杂
对于前序遍历来说无论是递归写法还是非递归写法
(class: MyBinarySearchTree, class: Main) MyBinarySearchTree
import java.util.Stack;
      public class MyBinarySearchTree<E extends Comparable<E>> {
            private class Node {
                public E e;
                public Node left, right;
                public Node (E e) {
                      this.e = e;
                      left = null;
                      right = null;
                }
            }
            private Node root;
            private int size;
            public MyBinarySearchTree () {
                  root = null;
                  size = 0;
            }
            public int getSize() {
                  return size;
            }
            public boolean isEmpty () {
                  return size == 0;
            }
            // 向二分搜索树中添加一个元素 e
            // 改进:直接调用add
            public void add (E e) {
                  root = add(root, e);
            }
            // 向以node为根的二分搜索树中插入元素E,递归算法
            // 改进:返回插入的新节点后二分搜索树的根
            private Node add (Node node, E e) {
                  // 处理最基本的问题
                  if (node == null) {
                        size ++;
                        return new Node(e);
                  }
                  // 空的二叉树也是叉树。
                  if (e.compareTo(node.e) < 0) {
                        // 将处理后的结果赋值给node的左子树
                        node.left =  add(node.left, e);
                  } else if (e.compareTo(node.e) > 0) {
                        // 将处理后的结果赋值给node的右子树
                        node.right =  add(node.right, e);
                  } // 如果相同 就什么都不做
                  // 最后返回这个node
                  return node;
            }
            // 查询二分搜索数中是否包含某个元素
            public boolean contains (E e) {
                  return contains(root, e);
            }
            // 向以node为根的二分搜索树 进行查找  递归算法
            private boolean contains (Node node, E e) {
                  // 解决最基本的问题 也就是遍历完所有节点都没有找到
                  if (node == null) {
                        return false;
                  }
                  // 如果 e 小于当前节点的e 则向左子树进发
                  if (e.compareTo(node.e) < 0) {
                      return contains(node.left, e);
                  } else if (e.compareTo(node.e) > 0) { // 如果 e 大于当前节点的e 则向右子树进发
                      return contains(node.right, e);
                  } else { // 如果e 等于 当前节点 e 则直接返回true
                        return true;
                  }
            }
            // 二分搜索树的前序遍历
            public void preOrder () {
                  preOrder(root);
            }
            // 前序遍历以node为根的二分搜索树 递归算法
            private void preOrder (Node node) {
                  if (node == null) {
                        return;
                  }
                  // 输出
                  System.out.println(node.e);
                  preOrder(node.left);
                  preOrder(node.right);
      //        // 这种逻辑也是可以的
      //        if (node != null) {
      //            // 输出
      //            System.out.println(node.e);
      //
      //            preOrder(node.left);
      //            preOrder(node.right);
      //        }
            }
            // 二分搜索树的前序遍历 非递归算法
            public void preOrderNonRecursive () {
                  Stack<Node> stack = new Stack<Node>();
                  stack.push(root);
                  Node node = null;
                  while (!stack.isEmpty()) {
                        node = stack.pop();
      //            // 第一种写法 不符合要求也可以压入栈,但是不符合要求的在出栈后不处理它
      //            if (node != null) {
      //                System.out.println(node.e);
      //                stack.push(node.right);
      //                stack.push(node.left);
      //            }
      //            // 第二种写法 不符合要求也可以压入栈,但是不符合要求的在出栈后不处理它
      //            if (node == null) continue;
      //
      //            System.out.println(node.e);
      //            stack.push(node.right);
      //            stack.push(node.left);
                        // 写法三 不符合要求就不压入栈
                        System.out.println(node.e);
                        if (node.right != null) {
                              stack.push(node.right);
                        }
                        if (node.left != null) {
                              stack.push(node.left);
                        }
                  }
            }
            // 二分搜索树的中序遍历
            public void inOrder () {
                  inOrder(root);
            }
            // 中序遍历以node为根的二分搜索树 递归算法
            private void inOrder (Node node) {
                  if (node == null) return;
                  inOrder(node.left);
                  System.out.println(node.e);
                  inOrder(node.right);
            }
            // 二分搜索树的中序遍历 非递归算法
            public void inOrderNonRecursive () {
            }
            // 二分搜索树的后序遍历
            public void postOrder () {
                  postOrder(root);
            }
            // 后续遍历以node为根的二分搜索树 递归算法
            private void postOrder (Node node) {
                  if (node == null) return;
                  postOrder(node.left);
                  postOrder(node.right);
                  System.out.println(node.e);
            }
            @Override
            public String toString () {
                  StringBuilder sb = new StringBuilder();
                  generateBSTString(root, 0, sb);
                  return sb.toString();
            }
            // 生成以node为根节点,深度为depth的描述二叉树的字符串
            private void generateBSTString (Node node, int depath, StringBuilder sb) {
                  if (node == null) {
                        sb.append(generateDepthString(depath) + "null/n");
                        return;
                  }
                  sb.append(generateDepthString(depath) + node.e + "/n");
                  generateBSTString(node.left, depath + 1, sb);
                  generateBSTString(node.right, depath + 1, sb);
            }
            // 生成路径字符串
            private String generateDepthString (int depth) {
                  StringBuilder sb = new StringBuilder();
                  for (int i = 0; i < depth; i++) {
                        sb.append("-- ");
                  }
                  return  sb.toString();
            }
      } Main
public class Main {
         public static void main(String[] args) {
               MyBinarySearchTree<Integer> mbst = new MyBinarySearchTree<Integer>();
               int [] nums = {5, 3, 6, 8, 4, 2};
               for (int i = 0; i < nums.length ; i++) {
                     mbst.add(nums[i]);
               }
               /////////////////
               //      5      //
               //    /   /    //
               //   3    6    //
               //  / /    /   //
               // 2  4     8  //
               /////////////////
               // 前序遍历
               mbst.preOrder(); // 5 3 2 4 6 8
               System.out.println();
               // 中序遍历
               mbst.inOrder(); // 2 3 4 5 6 8
               System.out.println();
               // 后序遍历
               mbst.postOrder(); // 2 4 3 8 6 5
               System.out.println();
               // 前序遍历 非递归
               mbst.preOrderNonRecursive(); // 5 3 2 4 6 8
               System.out.println();
   //        // 输出 调试字符串
   //        System.out.println(mbst.toString());
         }
   } 二分搜索树的 前序、中序、后序遍历
对于二分搜索树来说
先遍历第 0 层、再遍历第 1 层、再遍历下一层,
对于层序遍历的实现或者广度优先遍历的实现
先入队根节点,然后看队首是否有元素,
相对于深度优先遍历来说,广度优先遍历的优点
在图中也是有深度优先遍历和广度优先遍历的
(class: MyBinarySearchTree, class: Main) MyBinarySearchTree
import java.util.LinkedList;
   import java.util.Queue;
   import java.util.Stack;
   public class MyBinarySearchTree<E extends Comparable<E>> {
         private class Node {
             public E e;
             public Node left, right;
             public Node (E e) {
                   this.e = e;
                   left = null;
                   right = null;
             }
         }
         private Node root;
         private int size;
         public MyBinarySearchTree () {
               root = null;
               size = 0;
         }
         public int getSize() {
               return size;
         }
         public boolean isEmpty () {
               return size == 0;
         }
         // 向二分搜索树中添加一个元素 e
         // 改进:直接调用add
         public void add (E e) {
               root = add(root, e);
         }
         // 向以node为根的二分搜索树中插入元素E,递归算法
         // 改进:返回插入的新节点后二分搜索树的根
         private Node add (Node node, E e) {
               // 处理最基本的问题
               if (node == null) {
                     size ++;
                     return new Node(e);
               }
               // 空的二叉树也是叉树。
               if (e.compareTo(node.e) < 0) {
                     // 将处理后的结果赋值给node的左子树
                     node.left =  add(node.left, e);
               } else if (e.compareTo(node.e) > 0) {
                     // 将处理后的结果赋值给node的右子树
                     node.right =  add(node.right, e);
               } // 如果相同 就什么都不做
               // 最后返回这个node
               return node;
         }
         // 查询二分搜索数中是否包含某个元素
         public boolean contains (E e) {
               return contains(root, e);
         }
         // 向以node为根的二分搜索树 进行查找  递归算法
         private boolean contains (Node node, E e) {
               // 解决最基本的问题 也就是遍历完所有节点都没有找到
               if (node == null) {
                     return false;
               }
               // 如果 e 小于当前节点的e 则向左子树进发
               if (e.compareTo(node.e) < 0) {
                   return contains(node.left, e);
               } else if (e.compareTo(node.e) > 0) { // 如果 e 大于当前节点的e 则向右子树进发
                   return contains(node.right, e);
               } else { // 如果e 等于 当前节点 e 则直接返回true
                     return true;
               }
         }
         // 二分搜索树的前序遍历
         public void preOrder () {
               preOrder(root);
         }
         // 前序遍历以node为根的二分搜索树 递归算法
         private void preOrder (Node node) {
               if (node == null) {
                     return;
               }
               // 输出
               System.out.println(node.e);
               preOrder(node.left);
               preOrder(node.right);
   //        // 这种逻辑也是可以的
   //        if (node != null) {
   //            // 输出
   //            System.out.println(node.e);
   //
   //            preOrder(node.left);
   //            preOrder(node.right);
   //        }
         }
         // 二分搜索树的前序遍历 非递归算法
         public void preOrderNonRecursive () {
               Stack<Node> stack = new Stack<Node>();
               stack.push(root);
               Node node = null;
               while (!stack.isEmpty()) {
                     node = stack.pop();
   //            // 第一种写法 不符合要求也可以压入栈,但是不符合要求的在出栈后不处理它
   //            if (node != null) {
   //                System.out.println(node.e);
   //                stack.push(node.right);
   //                stack.push(node.left);
   //            }
   //            // 第二种写法 不符合要求也可以压入栈,但是不符合要求的在出栈后不处理它
   //            if (node == null) continue;
   //
   //            System.out.println(node.e);
   //            stack.push(node.right);
   //            stack.push(node.left);
                     // 写法三 不符合要求就不压入栈
                     System.out.println(node.e);
                     if (node.right != null) {
                           stack.push(node.right);
                     }
                     if (node.left != null) {
                           stack.push(node.left);
                     }
               }
         }
         // 二分搜索树的中序遍历
         public void inOrder () {
               inOrder(root);
         }
         // 中序遍历以node为根的二分搜索树 递归算法
         private void inOrder (Node node) {
               if (node == null) return;
               inOrder(node.left);
               System.out.println(node.e);
               inOrder(node.right);
         }
         // 二分搜索树的中序遍历 非递归算法
         public void inOrderNonRecursive () {
         }
         // 二分搜索树的后序遍历
         public void postOrder () {
               postOrder(root);
         }
         // 后续遍历以node为根的二分搜索树 递归算法
         private void postOrder (Node node) {
               if (node == null) return;
               postOrder(node.left);
               postOrder(node.right);
               System.out.println(node.e);
         }
         // 二分搜索树的层序遍历
         public void levelOrder () {
               // java中的Queue是一个接口,但是它有链表和队列的实现,
               // 所以你可以new 一个子类链表类来进行进行使用,可以达到同样的效果
               Queue<Node> queue = new LinkedList<Node>();
               queue.add(root);
               while (!queue.isEmpty()) {
                     Node node = queue.remove();
                     System.out.println(node.e);
                     if (node.left != null) {
                           queue.add(node.left);
                     }
                     if (node.right != null) {
                           queue.add(node.right);
                     }
               }
         }
         @Override
         public String toString () {
               StringBuilder sb = new StringBuilder();
               generateBSTString(root, 0, sb);
               return sb.toString();
         }
         // 生成以node为根节点,深度为depth的描述二叉树的字符串
         private void generateBSTString (Node node, int depath, StringBuilder sb) {
               if (node == null) {
                     sb.append(generateDepthString(depath) + "null/n");
                     return;
               }
               sb.append(generateDepthString(depath) + node.e + "/n");
               generateBSTString(node.left, depath + 1, sb);
               generateBSTString(node.right, depath + 1, sb);
         }
         // 生成路径字符串
         private String generateDepthString (int depth) {
               StringBuilder sb = new StringBuilder();
               for (int i = 0; i < depth; i++) {
                     sb.append("-- ");
               }
               return  sb.toString();
         }
   } Main
public class Main {
         public static void main(String[] args) {
               MyBinarySearchTree<Integer> mbst = new MyBinarySearchTree<Integer>();
               int [] nums = {5, 3, 6, 8, 4, 2};
               for (int i = 0; i < nums.length ; i++) {
                     mbst.add(nums[i]);
               }
               /////////////////
               //      5      //
               //    /   /    //
               //   3    6    //
               //  / /    /   //
               // 2  4     8  //
               /////////////////
   //        // 前序遍历
   //        mbst.preOrder(); // 5 3 2 4 6 8
   //        System.out.println();
   //
   //        // 中序遍历
   //        mbst.inOrder(); // 2 3 4 5 6 8
   //        System.out.println();
   //
   //        // 后序遍历
   //        mbst.postOrder(); // 2 4 3 8 6 5
   //        System.out.println();
   //
   //        // 前序遍历 非递归
   //        mbst.preOrderNonRecursive(); // 5 3 2 4 6 8
   //        System.out.println();
               mbst.levelOrder(); // 5 3 6 2 4 8
               System.out.println();
   //        // 输出 调试字符串
   //        System.out.println(mbst.toString());
         }
   } 很多时候学习知识
对于二分搜索树来说删除一个节点相对来说是比较复杂的
删除二分搜索树的最小值和最大值
找到二分搜索树中的最大值和最小值是非常容易的
删除最大元素节点
删除最小元素节点
(class: MyBinarySearchTree, class: Main) MyBinarySearchTree
import java.util.LinkedList;
   import java.util.Queue;
   import java.util.Stack;
   public class MyBinarySearchTree<E extends Comparable<E>> {
         private class Node {
             public E e;
             public Node left, right;
             public Node (E e) {
                   this.e = e;
                   left = null;
                   right = null;
             }
         }
         private Node root;
         private int size;
         public MyBinarySearchTree () {
               root = null;
               size = 0;
         }
         public int getSize() {
               return size;
         }
         public boolean isEmpty () {
               return size == 0;
         }
         // 向二分搜索树中添加一个元素 e
         // 改进:直接调用add
         public void add (E e) {
               root = add(root, e);
         }
         // 向以node为根的二分搜索树中插入元素E,递归算法
         // 改进:返回插入的新节点后二分搜索树的根
         private Node add (Node node, E e) {
               // 处理最基本的问题
               if (node == null) {
                     size ++;
                     return new Node(e);
               }
               // 空的二叉树也是叉树。
               if (e.compareTo(node.e) < 0) {
                     // 将处理后的结果赋值给node的左子树
                     node.left =  add(node.left, e);
               } else if (e.compareTo(node.e) > 0) {
                     // 将处理后的结果赋值给node的右子树
                     node.right =  add(node.right, e);
               } // 如果相同 就什么都不做
               // 最后返回这个node
               return node;
         }
         // 查询二分搜索数中是否包含某个元素
         public boolean contains (E e) {
               return contains(root, e);
         }
         // 向以node为根的二分搜索树 进行查找  递归算法
         private boolean contains (Node node, E e) {
               // 解决最基本的问题 也就是遍历完所有节点都没有找到
               if (node == null) {
                     return false;
               }
               // 如果 e 小于当前节点的e 则向左子树进发
               if (e.compareTo(node.e) < 0) {
                   return contains(node.left, e);
               } else if (e.compareTo(node.e) > 0) { // 如果 e 大于当前节点的e 则向右子树进发
                   return contains(node.right, e);
               } else { // 如果e 等于 当前节点 e 则直接返回true
                     return true;
               }
         }
         // 二分搜索树的前序遍历
         public void preOrder () {
               preOrder(root);
         }
         // 前序遍历以node为根的二分搜索树 递归算法
         private void preOrder (Node node) {
               if (node == null) {
                     return;
               }
               // 输出
               System.out.println(node.e);
               preOrder(node.left);
               preOrder(node.right);
   //        // 这种逻辑也是可以的
   //        if (node != null) {
   //            // 输出
   //            System.out.println(node.e);
   //
   //            preOrder(node.left);
   //            preOrder(node.right);
   //        }
         }
         // 二分搜索树的前序遍历 非递归算法
         public void preOrderNonRecursive () {
               Stack<Node> stack = new Stack<Node>();
               stack.push(root);
               Node node = null;
               while (!stack.isEmpty()) {
                     node = stack.pop();
   //            // 第一种写法 不符合要求也可以压入栈,但是不符合要求的在出栈后不处理它
   //            if (node != null) {
   //                System.out.println(node.e);
   //                stack.push(node.right);
   //                stack.push(node.left);
   //            }
   //            // 第二种写法 不符合要求也可以压入栈,但是不符合要求的在出栈后不处理它
   //            if (node == null) continue;
   //
   //            System.out.println(node.e);
   //            stack.push(node.right);
   //            stack.push(node.left);
                     // 写法三 不符合要求就不压入栈
                     System.out.println(node.e);
                     if (node.right != null) {
                           stack.push(node.right);
                     }
                     if (node.left != null) {
                           stack.push(node.left);
                     }
               }
         }
         // 二分搜索树的中序遍历
         public void inOrder () {
               inOrder(root);
         }
         // 中序遍历以node为根的二分搜索树 递归算法
         private void inOrder (Node node) {
               if (node == null) return;
               inOrder(node.left);
               System.out.println(node.e);
               inOrder(node.right);
         }
         // 二分搜索树的中序遍历 非递归算法
         public void inOrderNonRecursive () {
         }
         // 二分搜索树的后序遍历
         public void postOrder () {
               postOrder(root);
         }
         // 后续遍历以node为根的二分搜索树 递归算法
         private void postOrder (Node node) {
               if (node == null) return;
               postOrder(node.left);
               postOrder(node.right);
               System.out.println(node.e);
         }
         // 二分搜索树的层序遍历
         public void levelOrder () {
               // java中的Queue是一个接口,但是它有链表和队列的实现,
               // 所以你可以new 一个子类链表类来进行进行使用,可以达到同样的效果
               Queue<Node> queue = new LinkedList<Node>();
               queue.add(root);
               while (!queue.isEmpty()) {
                     Node node = queue.remove();
                     System.out.println(node.e);
                     if (node.left != null) {
                           queue.add(node.left);
                     }
                     if (node.right != null) {
                           queue.add(node.right);
                     }
               }
         }
         // 寻找二分搜索树的最小值元素
         public E minimum () {
               if (size == 0) {
                     throw new IllegalArgumentException("BST is empty.");
               }
               return minimum(root).e;
         }
         // 返回以node为根的二分搜索树的最小值所在的节点
         private Node minimum (Node node) {
               // 向左走再也走不动了,就返回这个节点。
               if (node.left == null) return node;
               return minimum(node.left);
         }
         // 从二分搜索树种删除最小值所在节点,返回这个最小值
         public E removeMin () {
               E result = minimum();
   //        removeMin(root);
               root = removeMin(root);
               return result;
         }
         // 删除掉以node为根的二分搜索树中的最小节点
         // 返回删除节点后新的二分搜索树的根
         private Node removeMin (Node node) {
   //        if (node.left == null) {
   //            node = node.right;
   //            size --;
   //            return node;
   //        }
   //
   //        return removeMin(node.left);
               if (node.left == null) {
                     Node rightNode = node.right;
                     node.right = null;
                     size --;
                     return rightNode;
               }
               node.left = removeMin(node.left);
               return node;
         }
         // 寻找二分搜索树的最大值元素
         public E maximum () {
               if (size == 0) {
                     throw new IllegalArgumentException("BST is empty.");
               }
               return maximum(root).e;
         }
         // 返回以node为根的二分搜索树的最大值所在的节点
         private Node maximum (Node node) {
               // 向右走再也走不动了,就返回这个节点。
               if (node.right == null) return node;
               return maximum(node.right);
         }
         // 从二分搜索树种删除最大值所在节点,返回这个最大值
         public E removeMax () {
               E result = maximum();
               root = removeMax(root);
               return result;
         }
         // 删除掉以node为根的二分搜索树中的最大节点
         // 返回删除节点后新的二分搜索树的根
         private Node removeMax (Node node) {
               if (node.right == null) {
                     Node leftNode = node.left;
                     node.left = null;
                     size --;
                     return leftNode;
               }
               node.right = removeMax(node.right);
               return node;
         }
         @Override
         public String toString () {
               StringBuilder sb = new StringBuilder();
               generateBSTString(root, 0, sb);
               return sb.toString();
         }
         // 生成以node为根节点,深度为depth的描述二叉树的字符串
         private void generateBSTString (Node node, int depath, StringBuilder sb) {
               if (node == null) {
                     sb.append(generateDepthString(depath) + "null/n");
                     return;
               }
               sb.append(generateDepthString(depath) + node.e + "/n");
               generateBSTString(node.left, depath + 1, sb);
               generateBSTString(node.right, depath + 1, sb);
         }
         // 生成路径字符串
         private String generateDepthString (int depth) {
               StringBuilder sb = new StringBuilder();
               for (int i = 0; i < depth; i++) {
                     sb.append("-- ");
               }
               return  sb.toString();
         }
   } Main
import java.util.ArrayList;
   import java.util.Random;
   public class Main {
         public static void main(String[] args) {
               MyBinarySearchTree<Integer> mbst = new MyBinarySearchTree<Integer>();
               Random random = new Random();
               int n = 100;
               for (int i = 0; i < n; i++) {
                     mbst.add(random.nextInt(Integer.MAX_VALUE));
               }
               // 动态数组
               ArrayList<Integer> arrayList = new ArrayList<Integer>();
               while (!mbst.isEmpty()) {
                     arrayList.add(mbst.removeMin());
   //            arrayList.add(mbst.removeMax());
               }
               // 数组中就是从小到大排序的
               System.out.println(arrayList);
               // 验证一下
               for (int i = 1; i < arrayList.size() ; i++) {
                     // 如果前面的数大于后面的数就报异常
                     if (arrayList.get(i - 1) > arrayList.get(i)) {
                           // 如果前面的数小于后面的数就报异常
   //            if (arrayList.get(i - 1) < arrayList.get(i)) {
                           throw new IllegalArgumentException("error.");
                     }
               }
               System.out.println("removeMin test completed.");
   //        System.out.println("removeMax test completed.");
         }
   } 在二分搜索树种删除最大值最小值的逻辑
删除二分搜索树上任意节点会发生的情况
对于二分搜索树来说
(class: MyBinarySearchTree, class: Main) MyBinarySearchTree
import java.util.LinkedList;
   import java.util.Queue;
   import java.util.Stack;
   public class MyBinarySearchTree<E extends Comparable<E>> {
         private class Node {
             public E e;
             public Node left, right;
             public Node (E e) {
                   this.e = e;
                   left = null;
                   right = null;
             }
         }
         private Node root;
         private int size;
         public MyBinarySearchTree () {
               root = null;
               size = 0;
         }
         public int getSize() {
               return size;
         }
         public boolean isEmpty () {
               return size == 0;
         }
         // 向二分搜索树中添加一个元素 e
         // 改进:直接调用add
         public void add (E e) {
               root = add(root, e);
         }
         // 向以node为根的二分搜索树中插入元素E,递归算法
         // 改进:返回插入的新节点后二分搜索树的根
         private Node add (Node node, E e) {
               // 处理最基本的问题
               if (node == null) {
                     size ++;
                     return new Node(e);
               }
               // 空的二叉树也是叉树。
               if (e.compareTo(node.e) < 0) {
                     // 将处理后的结果赋值给node的左子树
                     node.left =  add(node.left, e);
               } else if (e.compareTo(node.e) > 0) {
                     // 将处理后的结果赋值给node的右子树
                     node.right =  add(node.right, e);
               } // 如果相同 就什么都不做
               // 最后返回这个node
               return node;
         }
         // 查询二分搜索数中是否包含某个元素
         public boolean contains (E e) {
               return contains(root, e);
         }
         // 向以node为根的二分搜索树 进行查找  递归算法
         private boolean contains (Node node, E e) {
               // 解决最基本的问题 也就是遍历完所有节点都没有找到
               if (node == null) {
                     return false;
               }
               // 如果 e 小于当前节点的e 则向左子树进发
               if (e.compareTo(node.e) < 0) {
                   return contains(node.left, e);
               } else if (e.compareTo(node.e) > 0) { // 如果 e 大于当前节点的e 则向右子树进发
                   return contains(node.right, e);
               } else { // 如果e 等于 当前节点 e 则直接返回true
                     return true;
               }
         }
         // 二分搜索树的前序遍历
         public void preOrder () {
               preOrder(root);
         }
         // 前序遍历以node为根的二分搜索树 递归算法
         private void preOrder (Node node) {
               if (node == null) {
                     return;
               }
               // 输出
               System.out.println(node.e);
               preOrder(node.left);
               preOrder(node.right);
   //        // 这种逻辑也是可以的
   //        if (node != null) {
   //            // 输出
   //            System.out.println(node.e);
   //
   //            preOrder(node.left);
   //            preOrder(node.right);
   //        }
         }
         // 二分搜索树的前序遍历 非递归算法
         public void preOrderNonRecursive () {
               Stack<Node> stack = new Stack<Node>();
               stack.push(root);
               Node node = null;
               while (!stack.isEmpty()) {
                     node = stack.pop();
   //            // 第一种写法 不符合要求也可以压入栈,但是不符合要求的在出栈后不处理它
   //            if (node != null) {
   //                System.out.println(node.e);
   //                stack.push(node.right);
   //                stack.push(node.left);
   //            }
   //            // 第二种写法 不符合要求也可以压入栈,但是不符合要求的在出栈后不处理它
   //            if (node == null) continue;
   //
   //            System.out.println(node.e);
   //            stack.push(node.right);
   //            stack.push(node.left);
                     // 写法三 不符合要求就不压入栈
                     System.out.println(node.e);
                     if (node.right != null) {
                           stack.push(node.right);
                     }
                     if (node.left != null) {
                           stack.push(node.left);
                     }
               }
         }
         // 二分搜索树的中序遍历
         public void inOrder () {
               inOrder(root);
         }
         // 中序遍历以node为根的二分搜索树 递归算法
         private void inOrder (Node node) {
               if (node == null) return;
               inOrder(node.left);
               System.out.println(node.e);
               inOrder(node.right);
         }
         // 二分搜索树的中序遍历 非递归算法
         public void inOrderNonRecursive () {
         }
         // 二分搜索树的后序遍历
         public void postOrder () {
               postOrder(root);
         }
         // 后续遍历以node为根的二分搜索树 递归算法
         private void postOrder (Node node) {
               if (node == null) return;
               postOrder(node.left);
               postOrder(node.right);
               System.out.println(node.e);
         }
         // 二分搜索树的层序遍历
         public void levelOrder () {
               // java中的Queue是一个接口,但是它有链表和队列的实现,
               // 所以你可以new 一个子类链表类来进行进行使用,可以达到同样的效果
               Queue<Node> queue = new LinkedList<Node>();
               queue.add(root);
               while (!queue.isEmpty()) {
                     Node node = queue.remove();
                     System.out.println(node.e);
                     if (node.left != null) {
                           queue.add(node.left);
                     }
                     if (node.right != null) {
                           queue.add(node.right);
                     }
               }
         }
         // 寻找二分搜索树的最小值元素
         public E minimum () {
               if (size == 0) {
                     throw new IllegalArgumentException("BST is empty.");
               }
               return minimum(root).e;
         }
         // 返回以node为根的二分搜索树的最小值所在的节点
         private Node minimum (Node node) {
               // 向左走再也走不动了,就返回这个节点。
               if (node.left == null) return node;
               return minimum(node.left);
         }
         // 从二分搜索树种删除最小值所在节点,返回这个最小值
         public E removeMin () {
               E result = minimum();
   //        removeMin(root);
               root = removeMin(root);
               return result;
         }
         // 删除掉以node为根的二分搜索树中的最小节点
         // 返回删除节点后新的二分搜索树的根
         private Node removeMin (Node node) {
   //        if (node.left == null) {
   //            node = node.right;
   //            size --;
   //            return node;
   //        }
   //
   //        return removeMin(node.left);
               if (node.left == null) {
                     Node rightNode = node.right;
                     node.right = null;
                     size --;
                     return rightNode;
               }
               node.left = removeMin(node.left);
               return node;
         }
         // 寻找二分搜索树的最大值元素
         public E maximum () {
               if (size == 0) {
                     throw new IllegalArgumentException("BST is empty.");
               }
               return maximum(root).e;
         }
         // 返回以node为根的二分搜索树的最大值所在的节点
         private Node maximum (Node node) {
               // 向右走再也走不动了,就返回这个节点。
               if (node.right == null) return node;
               return maximum(node.right);
         }
         // 从二分搜索树种删除最大值所在节点,返回这个最大值
         public E removeMax () {
               E result = maximum();
               root = removeMax(root);
               return result;
         }
         // 删除掉以node为根的二分搜索树中的最大节点
         // 返回删除节点后新的二分搜索树的根
         private Node removeMax (Node node) {
               if (node.right == null) {
                     Node leftNode = node.left;
                     node.left = null;
                     size --;
                     return leftNode;
               }
               node.right = removeMax(node.right);
               return node;
         }
         // 从二分搜索树中删除元素e的节点
         public void remove (E e) {
               root = remove(root, e);
         }
         // 删除掉以node为根的二分搜索树中值为e的节点 递归算法
         // 返回删除节点后新的二分搜索树的根
         private Node remove(Node node, E e) {
               if (node == null) return null;
               if (e.compareTo(node.e) < 0) {
                     node.left = remove(node.left, e);
                     return node;
               } else if (e.compareTo(node.e) > 0) {
                     node.right = remove(node.right, e);
                     return node;
               } else { // e == node.e
                     // 待删除的节点左子树为空
                     if (node.left == null) {
                           Node rightNode = node.right;
                           node.right = null;
                           size --;
                           return rightNode;
                     }
                     // 待删除的节点右子树为空
                     if (node.right == null) {
                           Node leftNode = node.left;
                           node.left = null;
                           size --;
                           return leftNode;
                     }
                     // 待删除的节点左右子树都不为空的情况
                     // 找到比待删除节点大的最小节点,即待删除节点右子树的最小节点
                     // 用这个节点顶替待删除节点的位置
                     Node successor = minimum(node.right);
                     successor.right = removeMin(node.right);
                     // 在removeMin这个操作中维护了一次size --,但是并没有删除节点
                     // 所以这里要进行一次size ++操作
                     size ++;
                     successor.left = node.left;
                     // 让node这个节点与当前这个二分搜索树脱离关系
                     node.left = node.right = null;
                     // 维护一下size
                     size --;
                     return successor;
               }
         }
         @Override
         public String toString () {
               StringBuilder sb = new StringBuilder();
               generateBSTString(root, 0, sb);
               return sb.toString();
         }
         // 生成以node为根节点,深度为depth的描述二叉树的字符串
         private void generateBSTString (Node node, int depath, StringBuilder sb) {
               if (node == null) {
                     sb.append(generateDepthString(depath) + "null/n");
                     return;
               }
               sb.append(generateDepthString(depath) + node.e + "/n");
               generateBSTString(node.left, depath + 1, sb);
               generateBSTString(node.right, depath + 1, sb);
         }
         // 生成路径字符串
         private String generateDepthString (int depth) {
               StringBuilder sb = new StringBuilder();
               for (int i = 0; i < depth; i++) {
                     sb.append("-- ");
               }
               return  sb.toString();
         }
   } Main
import java.util.ArrayList;
   import java.util.Random;
   public class Main {
         public static void main(String[] args) {
               MyBinarySearchTree<Integer> mbst = new MyBinarySearchTree<Integer>();
               // 动态数组
               ArrayList<Integer> arrayList = new ArrayList<Integer>();
               Random random = new Random();
               int n = 10;
               for (int i = 0; i < n; i++) {
                     int value = random.nextInt(Integer.MAX_VALUE);
                     mbst.add(value);
                     arrayList.add(value);
               }
               // 输出二分搜索树
               System.out.println(mbst.getSize());
               // 输出数组中内容
               System.out.println(arrayList);
               for (int i = 0; i < arrayList.size(); i++) {
                     mbst.remove(arrayList.get(i));
               }
               // 输出二分搜索树
               System.out.println(mbst.getSize());
               System.out.println("remove test completed.");
         }
   } 可以非常方便的拿到二分搜索树中最大值和最小值,
也因为这个顺序性也可以对它进行 floor 和 ceil 的操作,
相应的二分搜索树还可以实现 rank 和 select 方法,
root.size
维护 depth 的二分搜索树
支持重复元素的二分搜索树
还可以通过维护每一个节点的 count 变量来实现重复元素的二分搜索树,
count++ count--
在二分搜索树中相应的变种其实大多是在 node 中维护一些数据
相关的习题可以去 leetcode 中找到,
https://leetcode-cn.com/tag/tree/
其它