二叉搜索树

建立二叉搜索树

  • 基本骨架

    //因为视频考虑到实用性 加了泛型、
    //E元素遵循Comparable接口 //extends Comparable 转化为组合 更加灵活
    class BinarySearchTree<E> {
      private Integer size = 0;
      public Node root;
      public Comparator comparator;
      public BinarySearchTree(Comparator comparator) {
          this.comparator = comparator;
      }
      public BinarySearchTree() {
      }
    
      public Integer size() {
          return size;
      }
    
      public boolean isEmpty() {
          //if(root==null)return true;
          //return false;
          return size == 0;
      }
      public boolean contains(E element) {
          return true;
      }
    }
  • 节点类

    class Node<E> {
      E element;
      Node<E> left;
      Node<E> right;
      Node<E> parent;
    
      public Node(E e, Node<E> parent) {
          this.element = e;
          this.parent = parent;
      }
    }
  • 节点处理器 我们就可以除了写输出外 还可以进行一些操作

    //节点处理器需要提取出来
    interface Visitor<E> {
      //---> abstract 增加一个stop 用于控制程序
      // 不太适合用一个全局变量然后作为参数 因为基本类型 所有的方法不是共用一个
      //boolean flag = true;
      //如果在处理器中进行拦截的话 递归还是在运行
      //改为 ---> visitor实现类 参考截图
      void visit(E element);
    }
  • 节点输出

      @Override
      public String toString() {
          StringBuffer sb = new StringBuffer();
          toString(root, sb, "");
          return sb.toString();
      }
    
      private void toString(Node node, StringBuffer sb, String prefix) {
          if (node == null) return;
          toString(node.left, sb, prefix + "L---");
          sb.append(prefix).append(node.element).append("\n");
          toString(node.right, sb, prefix + "R---");
      }
    }

需要指定比较方式 且 不允许为null

  • 比较器代码

      // e1==e2为等于0, e1>e2为大于0, e1<e2为小于0
      public int compare(E e1, E e2) {
          //return e1.compareTo(e2);
          if (comparator != null) return comparator.compare(e1, e2);
          else {
              //更加完美的比较器 如果没法比较 说明元素有问题
              return ((Comparable) e1).compareTo(e2);
          }
      }
    
      //节点不能为空
      private void elementNotNullCheck(E element) {
          if (element == null) throw new RuntimeException();
      }
  • 比较器的实现类

    //这样就可以自定义比较器
    //可以写为匿名类
    class MyComparator implements Comparator<Integer> {
      @Override
      public int compare(Integer t1, Integer t2) {
          return t2 - t1;
      }
    }

接口设计

  • 图解

    图片说明

  • 添加节点
      public void add(E element) {
          elementNotNullCheck(element);
          //添加的是第一个节点
          if (root == null) {
              root = new Node(element, null);
              size++;
              return;
          }
          //添加不是第一个节点
          Node<E> temp = root;
          Node<E> parent = null;
          int cmp = 0;
          while (temp != null) {
              parent = temp;
              cmp = compare(temp.element, element);
              if (cmp == 0) {
                  //覆盖掉原先的node 大部分是有必要的  直接赋值 Node的结构没有发生变化
                  temp.element = element;
                  return;
              } else if (cmp > 0) {
                  temp = temp.left;
              } else if (cmp < 0) {
                  temp = temp.right;
              }
          }
          //必须要一个父节点来操作 否则会报错 无法代替add效果
          //涉及到指针问题 直接赋值 temp 直接指针到新节点,而parent的对应子节点还是null
          //temp = new Node(val,parent);
          if (cmp > 0) {
              parent.left = new Node(element, parent);
          } else {
              parent.right = new Node(element, parent);
          }
          size++;
      }

前序遍历:树状结构展示(注意左右子树)

  • 代码

      //前序遍历
      public void preOrder(Node<E> node) {
          if (node == null) return;
          System.out.println(node.element);
          preOrder(node.left);
          preOrder(node.right);
      }
    
      public void preOrderRe(Node<E> node) {
          Stack<Node> stack = new Stack<Node>();
          stack.push(node);
          while (!stack.isEmpty()) {
              Node temp = stack.pop();
              if (temp != null) {
                  System.out.println(temp.element);
                  if (temp.right != null) {
                      stack.add(temp.right);
                  }
                  if (temp.left != null) {
                      stack.add(temp.left);
                  }
              }
          }
      }

中序遍历:二叉搜索树的中序遍历按升序或者降序处理节点

  • 代码

      //中序遍历
      public void midOrder(Node<E> node) {
          if (node == null) return;
          midOrder(node.left);
          System.out.println(node.element);
          midOrder(node.right);
      }
    
      public void midOrderRe(Node<E> node) {
          Stack<Node> stack = new Stack<Node>();
          Node temp = node;
          while (temp != null || !stack.isEmpty()) {
              while (temp != null) {
                  stack.push(temp);
                  temp = temp.left;
              }
              temp = stack.pop();
              System.out.println(temp.element);
              temp = temp.right;
          }
      }

后序遍历:适用于一些先子后父的操作

  • 代码

      //后序遍历
      public void postOrder(Node<E> node) {
          if (node == null) return;
          postOrder(node.left);
          postOrder(node.right);
          System.out.println(node.element);
      }
    
      public void postOrderRe(Node<E> node) {
          Stack<Node> stack = new Stack<Node>();
          Node temp = node;
          Node last = null;
          while (temp != null || !stack.isEmpty()) {
              while (temp != null) {
                  stack.push(temp);
                  temp = temp.left;
              }
              temp = stack.peek();
              if (temp.right == null || temp.right == last) {
                  System.out.println(temp.element);
                  stack.pop();
                  last = temp;
                  temp = null;
              } else {
                  temp = temp.right;
              }
          }
      }

层次遍历

  • 代码
      //层次遍历
      public void levelOrder(Node<E> node, Visitor<E> visitor) {
          if (node == null) return;
          Queue<Node> queue = new LinkedList<Node>();
          Node temp = node;
          queue.offer(node);  //不要用add
          while (!queue.isEmpty()) {
              node = queue.poll();
              //处理器提取出来
              visitor.visit(node.element);
              if (node.left != null) queue.add(node.left);
              if (node.right != null) queue.add(node.right);
          }
      }

计算高度 可以参考leetcode

  • 代码
    if(node==null) return 0;
    return 1+ Math.max(height(node.left),height(node.right));
    非递归就可用层次遍历 1 -- 2 -- 4 -- 8 ---...

    判断是不是完全二叉树

    遍历一个一个节点
    if(node.left==null&&node.right!=null) return false;
    还有一种情况是
    图片说明
    if(node.left!=null){
      queue.offer(node.left)
    }

翻转二叉树

  • 代码
    左右交换
    子节点递归

重构二叉树 前序+中序 参考leetcode

  • 代码
    class Solution {
      int index = 0;
      public TreeNode buildTree(int[] preorder, int[] inorder) {
          return createBuild(preorder,inorder,0,preorder.length-1);
      }
      public TreeNode createBuild(int []preorder,int[]inorder,int start ,int end){
          if(start>end)return null;
          int val = preorder[index++];
          TreeNode root = new TreeNode(val);
          for (int i = 0; i < inorder.length; i++) {
              if(inorder[i]==val){
                  root.left = createBuild(preorder,inorder,start ,i-1);
                  root.right = createBuild(preorder,inorder,i+1 , end);
                  break;
              }
          }
          return root;
      }
    }

前驱结点

  • 讲解
    图片说明
  • 实现代码
      public Node<E> predecessor(Node<E> node) {
          if (node == null) return null;
          Node temp = null;
          if (node.left != null) {
              temp = node.left;
              while (temp.right != null) {
                  temp = temp.right;
              }
              return temp;
          }
          temp = node;
          while (temp.parent.left == temp && node.parent != null) {
              temp = temp.parent;
          }
          return temp.parent;
      }

后继节点

图片说明

删除节点--叶子节点

  • 直接删除 度为0
    图片说明

删除节点 ---度为1的节点 需要考虑parent的问题

图片说明

删除节点 度为2的节点

  • 前驱点或者后继点来取代自己
    图片说明
public class Solution {
    public static void main(String[] args) {
        BinarySearchTree bst = new BinarySearchTree();
        bst.add(7);
        bst.add(4);
        bst.add(9);
        bst.add(2);
        bst.add(5);
        bst.add(8);
        bst.add(11);
        bst.add(3);
        bst.add(12);
        bst.add(1);
        bst.remove(5);
        System.out.println(bst.toString());
        System.out.println("-----");
        bst.remove(11);
        System.out.println(bst.toString());
        System.out.println("-----");
        bst.remove(2);
        System.out.println(bst.toString());
        System.out.println("-----");
    }
}

class BinarySearchTree<E> {
    private Integer size = 0;
    public Node root;
    public Comparator comparator;

    public BinarySearchTree() {

    }

    public BinarySearchTree(Comparator comparator) {
        this.comparator = comparator;
    }

    public Integer size() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public boolean contains(E element) {
        if (findNode(element) != null) return true;
        return false;
    }

    public void remove(E element) {
        Node node = findNode(element);
        if (node == null) return;
        if (node.right != null && node.left != null) {
            Node temp = temp = predecessor(element);
            node.element = temp.element;
            node = temp;
        }
        //node这里度为1或者0  度为2已经转化成度为1或者0
        Node<E> replace = node.left != null ? node.left : node.right;
        if (replace != null) {              // 说明是度为1的节点
            replace.parent = node.parent;   //需要更改原先的parent的指向
            if (node.parent == null) {
                root = replace;
                //root.parent = null;
            } else if (node == node.parent.left) {
                node.parent.left = replace;
                //replace.parent = node.parent;  //需要更改原先的parent的指向
            } else if (node == node.parent.right) {
                node.parent.right = replace;
                //replace.parent = node.parent;
            }
        } else if (node.parent == null) {
            root = null;
        } else {
            if (node == node.parent.left) node.parent.left = null;
            else node.parent.right = null;
        }
        size--;
    }

    public void clear() {
        root = null;
    }

    public Node<E> predecessor(E element) {
        Node node = findNode(element);
        if (node == null) return null;
        Node temp = null;
        if (node.left != null) {
            temp = node.left;
            while (temp.right != null) {
                temp = temp.right;
            }
            return temp;
        }
        temp = node;
        while (temp.parent.left == temp && node.parent != null) {
            temp = temp.parent;
        }
        return temp.parent;
    }

    private Node<E> findNode(E e) {
        if (root == null || e == null) return null;
        Node<E> temp = root;
        while (temp != null) {
            if (compare(temp.element, e) > 0) {
                temp = temp.left;
            } else if (compare(temp.element, e) < 0) {
                temp = temp.right;
            } else {
                break;
            }
        }
        return temp;
    }

    public int compare(E e1, E e2) {
        //return e1.compareTo(e2);
        if (comparator != null) return comparator.compare(e1, e2);
        else {
            return ((Comparable) e1).compareTo(e2);
        }
    }

    private void elementNotNullCheck(E element) {
        if (element == null) throw new RuntimeException();
    }

    public void add(E element) {
        elementNotNullCheck(element);
        if (root == null) {
            root = new Node(element, null);
            size++;
            return;
        }
        Node<E> temp = root;
        Node<E> parent = null;
        int cmp = 0;
        while (temp != null) {
            parent = temp;
            cmp = compare(temp.element, element);
            if (cmp == 0) {
                temp.element = element;
                return;
            } else if (cmp > 0) {
                temp = temp.left;
            } else if (cmp < 0) {
                temp = temp.right;
            }
        }
        if (cmp > 0) {
            parent.left = new Node(element, parent);
        } else {
            parent.right = new Node(element, parent);
        }
        size++;
    }

    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer();
        toString(root, sb, "");
        return sb.toString();
    }

    private void toString(Node node, StringBuffer sb, String prefix) {
        if (node == null) return;
        toString(node.left, sb, prefix + "L---");
        sb.append(prefix).append(node.element).append("\n");
        toString(node.right, sb, prefix + "R---");
    }
}

class Node<E> {
    E element;
    Node<E> left;
    Node<E> right;
    Node<E> parent;

    public Node(E e, Node<E> parent) {
        this.element = e;
        this.parent = parent;
    }
}
全部评论

相关推荐

11-06 10:58
已编辑
门头沟学院 嵌入式工程师
双非25想找富婆不想打工:哦,这该死的伦敦腔,我敢打赌,你简直是个天才,如果我有offer的话,我一定用offer狠狠的打在你的脸上
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务