数据结构

二分搜索树

2019-08-18  本文已影响0人  将代码写成诗

原创作品,转载请标明来源。

一、 什么是二叉树?

editByWpp.png

二叉树每个节点最多有两个孩子
二叉树每个节点最多有一个父亲

性质

二、什么是二分搜索树?

editByWpp.png

注意:本文的二分搜索树不包含重复元素
如果想包含重复元素的话,只需要定义:左子树小于等于节点;或者柚子树大于节点即可

二分搜索树的增删茶

二分搜索树添加元素的非递归写法,和链表很像
本文在二分搜索树方面的实现,关注递归实现

public class BST<E extends Comparable<E>> {

private class Node{
   public   E e;
   public Noe left, right;
   public Node(E e) {
      this.e = e;
      left = null;
      right = null;
}
// 向二分搜索树中添加新的元素e -- 优化前
    public void add1(E e) {
        if (root == null) {
            root = new Node(e);
            size++;
        } else {
            add(root,e);
        }
    }

    // 向以node为根的二分搜索树中插入元素E,递归算法---优化前的插入元素部分
    private void add1(Node node, E e) {
        // 递归终止条件
       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 && node.left != null) {
           add(node.left,e);
       } else{ // (e.compareTo(node.e) > 0 && node.right != null)
           add(node.right,e);
       }
    }
    // 向二分搜索树中添加新的元素e -- 优化后
    public void add(E e) {
       root = add(root,e);
    }
    // 向以node为根的二分搜索树中插入元素E,递归算法---优化后的插入元素部分
    // null 也是一个二叉树来考虑
    private Node add(Node node, E e) {
        // 递归终止条件
        if (node == null) {
            size++;
            return new Node(e);
        }
       if (e.compareTo(node.e) < 0) {
          node.left = add(node.left,e);
       } else if (e.compareTo(node.e) > 0) {
           node.right = add(node.right,e);
       }
       return node;
    }
}
// 递归算法
    private boolean contains(Node node, E e) {
        if (node == null)
            return false;
        if (e.compareTo(node.e) == 0)
            return true;
        else if (e.compareTo(node.e) < 0)
            return contains(node.left,e);
        else //e.compareTo(node.e) > 0
            return contains(node.right,e);
    }
editByWpp.png
前序遍历
 public void preOrder() {
        System.out.println();
        preOrder(root);
    }
   private void preOrder(Node node) {
        if (node == null)
            return;
        System.out.println(node.e);
        preOrder(node.left);
        preOrder(node.right);
    }

    // 非递归的前序遍历
    public void preOrderNR (){

        Stack<Node> stack = new Stack();
        stack.push(root);
        while (!stack.isEmpty()) {
            Node cur = stack.pop();
            System.out.println(cur.e);
            if (cur.right != null) stack.push(cur.right);
            if (cur.left != null)  stack.push(cur.left);
        }
    }
中序遍历
    /**
     * 中序遍历
      */
    public void inOrder(){
        System.out.println();
        inOrder(root);
    }

    private void inOrder(Node node) {
        if (node == null)
            return;
        inOrder(node.left);
        System.out.print(node.e+ "  ");
        inOrder(node.right);
    }
    /**
     * 后序遍历
     */
    public void postOrder() {
        System.out.println();
        postOrder(root);
    }

    private void postOrder(Node node) {
        if (node == null) return;
        postOrder(node.left);
        postOrder(node.right);
        System.out.print(node.e+"  ");
    }

   public void levelOrder (){
        LinkedListQueue <Node> queue = new LinkedListQueue();
        queue.enqueue(root);
        while (!queue.isEmpty()) {
            Node cur = queue.dequeue();
            System.out.println(cur.e);
            if (cur.left != null)   queue.enqueue(cur.left);
            if (cur.right != null)  queue.enqueue(cur.right);

        }
    }
// 得到最小节点值
    public E miniMum(){
        if (size == 0)
            throw new IllegalArgumentException("BST is empty");
       return miniMum(root).e;
    }
    private Node miniMum(Node node) {
        if (node.left == null)
            return node;
        return miniMum(node.left);
    }
// 得到醉倒节点值
    public E maxMum(){
        if (size == 0)
            throw new IllegalArgumentException("BST is empty");
        return maxMum(root).e;
    }
    private Node maxMum(Node node) {
        if (node.right == null)
            return node;
        return maxMum(node.right);
    }
 public E removeMin(){
        E  ret = miniMum();
        root = removeMin(root);
        return ret;
    }
    // 删除掉以node为根的二分搜索树中的最小节点
    // 返回删除节点后新的二分搜索树的根
    private Node removeMin(Node node) {
        if (node.left == null) {
            Node rightNode = node.right;
            node.right = null;
            size--;
            return rightNode;
        }
        node.left = removeMin(node.left);
        return node;
    }
   public E removeMax(){
        E  ret = maxMum();
        root = removeMax(root);
        return ret;
    }
    // 删除掉以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;
    }

当我们试图删除某一个节点时,如果这个节点只有左节点,没有右节点,我们可以以删除最大节点的方式去处理(即使该节点未必是最大节点),如果只有右节点没有左节点时,我们同样可以将它以删除最小节点的方式去处理,问题是如果这个要删除的节点既有左节点又有右节点时,怎么处理呢?
我引入一句话,给出了方案

1962年,Hibgard提出- Hibgard Deletion
其实也很简单,就是找到待删除节点的后置最小节点替代待删节点;

比如下图中,d节点是待删节点,根据二分搜索树的性质,d节点的右子叶都比左子叶要打,那么我们只要找到右子叶的最小值替代当前待删节点就可以了。


editByWpp.png

另一种方案:也可以找到待删节点的前驱最大节点替代待删节点。如上图其实也可以用53所在的节点替换d节点;

写在后面

好了,现在二分搜索树的分析暂时可以告一段落了,

上一篇下一篇

猜你喜欢

热点阅读