0    课程地址

https://coding.imooc.com/lesson/207.html#mid=13477

 

1    重点关注

1.1    前驱和后继

前驱是左子节点最大的要素,一般是左子节点的右子节点的右子节点(无限循环到节点结束)。

后继是右子节点的最小要素,一般是又子节点的左子节点的左子节点(无限循环到节点结束)。

 

 

1.2    二分搜索树 查找 删除 最小 最大 元素代码实现

见3.1

 

2    课程内容

 

 

3    Coding

3.1    二分搜索树 删除任意元素

  • 关键代码
/**
     * 删除任意元素 若删除元素节点下只有一个节点直接接上即可,若有两个节点,则找前驱或后继,本节找前驱
     * @author weidoudou
     * @date 2022/11/18 7:37
     * @return void
     **/
    public void remove(E e){
        remove(root,e);
    }

    private Node remove(Node node,E e){
        //终止条件1
        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{
            //已找到要删除的元素
            //1 如果只有左子节点或只有右子节点,则直接将子节点替换
            if(node.left==null){
                return node.right;
            }else if(node.right==null){
                return node.left;
            }else{
                //2 如果有左子节点和右子节点,则寻找前驱或后继 对当前节点替换掉
                Node nodeMain = findMin(node.right);
                nodeMain.right = removMax(node.right);//这块一箭双雕,既把后继节点问题解决了,也把后继删除了
                nodeMain.left = node.left;
                node.left = node.right = null;
                return node;
            }
        }
    }

 

 

  • 全量代码
package com.company;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

public class BST2<E extends Comparable> {

    //1     内部类
    private class Node{
        //二叉树特有属性
        private Node left,right;
        private E e;
        private Node(E e){
            this.e = e;
            this.left = null;
            this.right = null;
        }
    }

    private int size;
    private Node root;

    public BST2(){
        this.size = 0;
        this.root = null;
    }

    /**
     * 定义基本方法 getSize
     * @author weidoudou
     * @date 2022/11/3 12:57
     * @return int
     **/
    public int getSize(){
        return size;
    }

    /**
     *查询是否为空
     * @author weidoudou
     * @date 2022/11/3 12:58
     * @return boolean
     **/
    public boolean isEmpty(){
        return size == 0;
    }

    //2     循环添加元素,把null也看作节点
    public void add(E e){
        root = add(e,root);
    }

    //3     递归,添加元素
    public Node add(E e,Node root){
        //3.1   终止条件
        if(root==null){
            size++;
            return new Node(e);
        }

        //3.2   递归
        //3.2.1 递归左孩子
        if(e.compareTo(root.e)<0){
            root.left = add(e,root.left);
        }

        //3.2.2 递归右孩子
        if(e.compareTo(root.e)>0){
            root.right = add(e,root.right);
        }

        //点睛之笔
        return root;
    }

    /**
     * 二分搜索树 是否包含元素e
     * @author weidoudou
     * @date 2022/11/4 9:55
     * @param e 请添加参数描述
     * @return boolean
     **/
    public boolean contains(E e){
        return contains(e,root);
    }

    /**
     * 二分搜索树查询 递归
     * @author weidoudou
     * @date 2022/11/4 9:57
     * @param e 请添加参数描述
     * @param  node 请添加参数描述
     * @return boolean
     **/
    private boolean contains(E e,Node node){
        //终止条件
        if(node == null){
            return false;
        }
        if(e.compareTo(node.e)==0){
            return true;
        }

        //递归条件
        if(e.compareTo(node.e)<0){
            return contains(e,node.left);
        }else{
            return contains(e,node.right);
        }

    }

    /**
     * 4     二分搜索树,前序遍历 顾名思义,先遍历根节点,再遍历左节点,最后遍历右节点
     * @author weidoudou
     * @date 2022/11/5 14:54
     * @return null
     **/
    public boolean preOrder(){
        preOrder(root);
        return false;
    }

    //前序遍历 递归
    private void preOrder(Node node){
        //终止条件
        if(node==null){
            return;
        }

        //递归
        System.out.println(node.e);//1
        preOrder(node.left);
        preOrder(node.right);
    }

    /**
     *  前序遍历非递归写法 用栈的方法实现 while 代替递归
     * @author weidoudou
     * @date 2022/11/8 9:57
     *
     * @return*/
    public boolean preOrderNR(){
        Stack<Node> stack = new Stack<>();
        stack.push(root);

        while(!stack.isEmpty()){
            Node cur = stack.peek();
            stack.pop();
            System.out.println(cur.e);
            if(cur.right!=null){
                stack.push(cur.right);
            }

            if(cur.left!=null){
                stack.push(cur.left);
            }
        }
        return false;
    }

    /**
     * 二分搜索树广度遍历
     * @author weidoudou
     * @date 2022/11/8 11:23
     * @return boolean
     **/
    public boolean levelOrder(){
        Queue<Node> queue = new LinkedList<>();
        queue.add(root);

        while (queue.peek()!=null){
            Node cur = queue.peek();
            System.out.println(cur.e);
            queue.remove();
            if(cur.left!=null){
                queue.add(cur.left);
            }
            if(cur.right!=null){
                queue.add(cur.right);
            }
        }
        return false;
    }


    /**
     * 5     二分搜索树,中序遍历 顾名思义,先遍历左节点,再遍历根节点,最后遍历右节点
     * @author weidoudou
     * @date 2022/11/5 14:54
     * @return null
     **/
    public boolean inOrder(){
        inOrder(root);
        return false;
    }

    //前序遍历 递归
    private void inOrder(Node node){
        //终止条件
        if(node==null){
            return;
        }

        //递归
        inOrder(node.left);
        System.out.println(node.e);//1
        inOrder(node.right);
    }

    /**
     * 6     二分搜索树,后序遍历 顾名思义,先遍历左节点,再遍历右节点,最后遍历根节点
     * @author weidoudou
     * @date 2022/11/5 14:54
     * @return null
     **/
    public boolean postOrder(){
        postOrder(root);
        return false;
    }

    //前序遍历 递归
    private void postOrder(Node node){
        //终止条件
        if(node==null){
            return;
        }

        //递归
        postOrder(node.left);
        postOrder(node.right);
        System.out.println(node.e);//1

    }



    /**
     * 基于前序遍历完成toString打印
     * @author weidoudou
     * @date 2022/11/5 15:20
     * @return java.lang.String
     **/
    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer();
        generate(root,0);
        return sb.toString();
    }

    private void generate(Node node, int depth){
        generate(depth);
        //1     终止条件
        if(node==null){
            System.out.println("null");
            return;
        }

        //2     递归条件
        System.out.println(node.e);
        depth++;
        generate(node.left,depth);
        generate(node.right,depth);
    }

    private void generate(int depth){
        for(int i = 0;i<depth;i++){
            System.out.print("==");
        }
    }

    /**
     * 7.1    查询最小的元素
     * @author weidoudou
     * @date 2022/11/8 14:30
     * @return E
     **/
    public E findMin(){
        if(size==0){
            throw new IllegalArgumentException("二叉树为空,无最小元素");
        }
        return findMin(root).e;
    }

    private Node findMin(Node node){
        //1     终止条件
        if(node.left==null){
            return node;
        }

        //2     递归
        return findMin(node.left);
    }

    /**
     * 7.2      查询最大的元素
     * @author weidoudou
     * @date 2022/11/8 14:30
     * @return E
     **/
    public E findMax(){
        if(size==0){
            throw new IllegalArgumentException("二叉树为空,无最大元素");
        }
        return findMax(root);
    }

    private E findMax(Node node){
        //1     终止条件
        if(node.right==null){
            return node.e;
        }

        //2     递归
        return findMax(node.right);
    }

    /**
     * 7.3      删除最小元素
     * @author weidoudou
     * @date 2022/11/8 15:43
     * @return void
     **/
    public E removMin(){
        E e = findMin();
        //这里好好思考下,为什么要加上root =
        //因为极端情况,最小值为根节点,不加这个的话,导致第一次删除后root不变,详见本节代码草图
        root = removMin(root);
        return e;
    }

    private Node removMin(Node node){
        //终止条件
        if(node.left==null){
            Node rightNode = node.right;
            node.right = null;
            size--;
            return rightNode;
        }

        //递归
        node.left = removMin(node.left);
        return node;
    }

    /**
     * 7.4      删除最大元素
     * @author weidoudou
     * @date 2022/11/8 15:43
     * @return void
     **/
    public E removMax(){
        E e = findMax();
        removMax(root);
        return e;
    }

    private Node removMax(Node node){
        //终止条件
        if(node.right==null){
            Node leftNode = node.left;
            node.left = null;
            size--;
            return leftNode;
        }

        //递归
        node.right = removMax(node.right);
        return node;
    }

    /**
     * 删除任意元素 若删除元素节点下只有一个节点直接接上即可,若有两个节点,则找前驱或后继,本节找前驱
     * @author weidoudou
     * @date 2022/11/18 7:37
     * @return void
     **/
    public void remove(E e){
        remove(root,e);
    }

    private Node remove(Node node,E e){
        //终止条件1
        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{
            //已找到要删除的元素
            //1 如果只有左子节点或只有右子节点,则直接将子节点替换
            if(node.left==null){
                return node.right;
            }else if(node.right==null){
                return node.left;
            }else{
                //2 如果有左子节点和右子节点,则寻找前驱或后继 对当前节点替换掉
                Node nodeMain = findMin(node.right);
                nodeMain.right = removMax(node.right);//这块一箭双雕,既把后继节点问题解决了,也把后继删除了
                nodeMain.left = node.left;
                node.left = node.right = null;
                return node;
            }
        }
    }


}

 

posted on 2022-12-02 11:19  菜鸟乙  阅读(24)  评论(0编辑  收藏  举报