代码实现
import java.util.ArrayList; import java.util.List; public class MyBSTree <T extends Comparable<T>>{ //定义二叉搜索树的根节点 private Node root; private int size; //对二叉搜索树的添加方法:在二叉搜索树种添加一个结点/值 public boolean add(T value){ //这里不允许往二叉树中存储null值 无法比较大小 if (value == null) throw new IllegalArgumentException("parame is null"); //这里判断添加的时候树是否为空 if (isEmpty()){ //如果原树为空,新元素作为根节点 root = new Node(value); size++; return true; } //原树不空 找一个存储位置,按照大小向左右方向上查找比较 Node mid = root;//当前遍历节点 Node midF = null;//保存遍历节点的父节点 int com = 0; while (mid != null){ com = value.compareTo(mid.value); midF = mid; if (com > 0){ //说明value比mid大 应该添加到mid的右边 mid = mid.right; }else if (com < 0){ mid = mid.left; }else{ //如果两值相等的话说明要添加的这个元素已经在树上了 以下讨论几个方法 // 拉链法 // 计数法 // 修正的BSTree return false; } } //midF就是要添加位置的父节点 if (com > 0){ //最后一次比较,value大 midF.right = new Node(value); }else{ //最后一次比较,value小 midF.left = new Node(value); } size++; return true; } /** * 对二叉搜索树的删除方法:在二叉搜索树种删除一个结点/值 * @return */ public boolean remove(T value){ //不允许在二叉树中出现null值 无法删除 if (value == null) throw new IllegalArgumentException("parame is null"); //二叉搜索树不能是空树 if (isEmpty()) throw new RuntimeException("tree is empty"); //查找要删除节点 Node mid = root;//遍历节点(用于查找要删除的结点) Node midF = null;//遍历结点的父节点 while (mid != null){ int com = value.compareTo(mid.value); if (com == 0){ //mid就是要删除的元素 break;//如果找到了就直接跳出循环 }else if (com > 0){ //value 比较大, 如果这个value存在在二叉搜索树, 应该在此时mid的right方向 midF = mid;//记录父结点位置 mid = mid.right;// 子结点右转 }else { // value 比较小, 如果这个value存在在二叉搜索树, 应该在此时mid的left方向 midF = mid;// 记录父结点位置 mid = mid.left;// 子结点左转 } } // 上述循环有两个跳出条件 // mid == null --> 没有找到, 这个树上没有存储这个元素 // 否则就是找到了 if (mid == null)return false; // mid就是找到的要删除结点位置 // midF 就是找到的要删除结点的父位置 // 先处理删除双分支情况 --> 替换 if (mid.left != null && mid.right != null){ // mid 的left 和right 都是不是 null // mid 是一个双分支结点: 先替换再删除 // 替换: (左子树最大值, 右子树最小值) 右子树的最小值 Node min = mid.right; Node minF = mid; while (min.left != null){ // mid 的left 还有结点, min不是最小, 接着向left移动找最小 minF = min; min = min.left; } // min就是mid 的right子树最小值 // minF 就是最小值的父结点 //替换值 mid.value = min.value; // 把要删除结点的引用, 指向这个已经完成替换的结点 mid = min; midF = minF; } // 再处理删除叶子或者单分支(双份支替换之后的叶子和单分支) // 拿到要删除结点的孩子 // (如果是个单分支,拿到那个不为null的孩子) // (如果本来就是叶子, 拿到null) Node ch = mid.left != null ? mid.left:mid.right; //TODO:特殊情况: 如果这个树的根节点是个单分支, 而且要删除的结点也是这个根节点 if (midF == null){ root = ch; size--; return true; } if (midF.left == mid){ // 删除的是midF 的left midF.left = ch; }else { // 删除的是midF 的right midF.right = ch; } size--; return true; } /** * 对二叉搜索树的查找方法:在二叉搜索树中查找某个值是否存在 * @return */ public boolean contains(T value){ //不允许输入null if(value == null) throw new IllegalArgumentException("parame is null"); //判断二叉搜索树是否为空 若为空肯定没有这个元素 if (isEmpty()) return false; //若二叉搜索树不空 Node mid = root;//定义一个遍历结点, 遍历 while (mid != null){ int com = value.compareTo(mid.value); if (com == 0){ // mid就是要查找的值 return true; }else if (com > 0){ // value更大, 如果value在树中存在, 那么在mid的right mid = mid.right; }else { // value更小, 如果value在树中存在, 那么在mid的left mid = mid.left; } } //没找到, mid == null return false; } public boolean isEmpty(){return size == 0;} public int size(){return size;} // -------------------------------------------------- // -------------------------------------------------- // -------------------------------------------------- // -------------------------------------------------- // -------------------------------------------------- // -------------------------------------------------- // -------------------------------------------------- // 前序: 栈, 递归 //用栈实现前序遍历 public List<T> preOrder(){ MyArrayStack<Node> stack = new MyArrayStack<>(); ArrayList<T> list = new ArrayList<>(); if (root == null)return list; //把根节点放入栈中 stack.push(root); while (!stack.isEmpty()){ Node mid = stack.pop(); list.add(mid.value); if (mid.right != null) stack.push(mid.right); if (mid.left != null) stack.push(mid.left); } return list; } //使用递归实现前序遍历 public void preOrder2(Node root, ArrayList<T> list){ //递归出口 if (root == null)return; //遍历根 list.add(root.value); //遍历左子树 preOrder2(root.left,list); //遍历右子树 preOrder2(root.right,list); } // 中序: 栈, 递归 // 用栈实现中序遍历 public List<T> inOrder(){ MyArrayStack<Node> stack = new MyArrayStack<>(); ArrayList<T> list = new ArrayList<>(); //定义一个标记结点 Node mid = root; // 循环: 栈不为空 或者 标记结点不是null while (!stack.isEmpty() || mid != null){ // 小循环: mid left序列统统入栈 while (mid!=null){ stack.push(mid); mid = mid.left; } // 出栈遍历 Node pop = stack.pop(); list.add(pop.value); // 标记结点指向出栈结点的right mid = pop.right; } return list; } public List<T> inOrder2(){ ArrayList<T> list = new ArrayList<>(); inOrder2(root , list); return list; } // 递归核心思想: 大问题转化成小问题 // 不要上来就想出口是什么, 也不要一开始就想怎么触发这个递归 // 问题的共性 --- 最重要, // 比如这个中序遍历, 如果给我一个结点, 遍历左子树, 遍历根 遍历右子树 // 递归实现中序遍历 private void inOrder2(Node root,ArrayList<T> list){ //出口 if (root == null)return; // 遍历左子树 inOrder2(root.left,list); // 遍历根 list.add(root.value); // 遍历右子树 inOrder2(root.right,list); } //后序:用栈,递归实现 // 用栈实现后序遍历 public List<T> posrOrder(){ MyArrayStack<Node> stack = new MyArrayStack<>(); ArrayList<T> list = new ArrayList<>(); //根节点入栈 stack.push(root); //循环 栈不为空 while (!stack.isEmpty()){ Node pop = stack.pop();//出栈元素 list.add(0, pop.value);//逆序遍历——头插法 if (pop.left != null)stack.push(pop.left); if (pop.right != null) stack.push(pop.right); } return list; } //使用递归逆序 public List<T> posrOrder2(){ ArrayList<T> list = new ArrayList<>(); posrOrder2(root,list); return list; } private void posrOrder2(Node root, ArrayList<T> list) { //出口 if (root == null)return; //遍历左子树 posrOrder2(root.left,list); // 遍历右子树 posrOrder2(root.right,list); // 遍历根 list.add(root.value); } //层级遍历 使用队列 public List<T> leOrder(){ MyArrayQueue<Node> queue = new MyArrayQueue<>(); ArrayList<T> list = new ArrayList<>(); // 根节点入队列 queue.offer(root); //循环 队列不空 while (!queue.isEmpty()){ //出队列一个元素遍历 Node poll = queue.poll(); list.add(poll.value); // 出队列结点的左右子结点入队列 if (poll.left != null)queue.offer(poll.left); if (poll.right != null)queue.offer(poll.right); } return list; } // 建树操作: 后序+中序 public void buildTreeByPostAndInOrder(List<T> postOrder, List<T> inOrder){ // 递归方法 root = buildTreeByPostAndInOrder2(postOrder, inOrder); size = inOrder.size(); } //后序: [-2, -1, 0, 1, 6, 7, 5, 13, 11, 20, 15, 10] //中序: [-2, -1, 0, 1, 5, 6, 7, 10, 11, 13, 15, 20] private Node buildTreeByPostAndInOrder2(List<T> postOrder, List<T> inOrder) { // 出口 if (postOrder.size() == 0)return null; if (postOrder.size() == 1){ return new Node(postOrder.get(0)); } // 获得根节点的值, 后序的最后一个元素 T rootValue = postOrder.get(postOrder.size() - 1); // 创建根节点 Node node = new Node(rootValue); // 获取根节点在中序中的位置 int index = inOrder.indexOf(rootValue); //后序: [-2, -1, 0, 1, 6, 7, 5, 13, 11, 20, 15, 10] 左 右 根 //中序: [-2, -1, 0, 1, 5, 6, 7, 10, 11, 13, 15, 20] 左 根 右 // index // 左子树left: // 中序: inOrder -> 0 - index-1 // 后序: postOrder-> 0 - index-1 // 右子树right: // 中序: inOrder -> index+1 - size-1 // 后序: postOrder-> index - size-2 List<T> leftInOder = inOrder.subList(0, index); List<T> leftPostOder = postOrder.subList(0, index); List<T> rightInOder = inOrder.subList(index+1, inOrder.size()); List<T> rightPostOder = postOrder.subList(index, inOrder.size() - 1); // 递归去构建node 的left子树和right子树 node.left = buildTreeByPostAndInOrder2(leftPostOder, leftInOder); node.right = buildTreeByPostAndInOrder2(rightPostOder, rightInOder); return node; } // 建树操作: 前序+中序 // 建树操作: 前序+中序 public void buildTreeByPreAndInOrder(List<T> preOrder, List<T> inOrder){ // 递归方法 root = buildTreeByPreAndInOrder2(preOrder, inOrder); size = inOrder.size(); } private Node buildTreeByPreAndInOrder2(List<T> preOrder, List<T> inOrder) { // 出口 if (preOrder.size() == 0)return null; if (preOrder.size() == 1){ return new Node(preOrder.get(0)); } // 获得根节点的值, 后序的最后一个元素 T rootValue = preOrder.get(preOrder.size() - 1); // 创建根节点 Node node = new Node(rootValue); // 获取根节点在中序中的位置 int index = inOrder.indexOf(rootValue); List<T> leftInOder = inOrder.subList(0, index); List<T> leftpreOder = preOrder.subList(0, index); List<T> rightInOder = inOrder.subList(index+1, inOrder.size()); List<T> rightpreOder = preOrder.subList(index, inOrder.size() - 1); // 递归去构建node 的left子树和right子树 node.left = buildTreeByPreAndInOrder2(leftpreOder, leftInOder); node.right = buildTreeByPreAndInOrder2(rightpreOder, rightInOder); return node; } //----------------------------------------------- class Node{ T value; Node left; Node right; public Node(T value){this.value = value;} } }