java实现并图解二叉搜索树的添加、查找以及删除方法(保姆级教程)

目录 

二叉搜索树的概念

实现二叉搜索树的添加方法

实现二叉搜索树的查找方法

实现二叉搜索树的删除方法

附带java代码


二叉搜索树的概念

二叉搜索树(二叉排序树):
1.首先是一棵二叉树
2.其次左子树上所有节点的值都小于根节点的值,右子树上所有节点的值都大于根节点的值。
图解:

实现二叉搜索树的添加方法

先讲解思路,再进行图解,最后实现代码

明确一个点:添加的位置是在叶子结点上

思路:
1.树为空,直接添加
2.树不为空,那就要判断是放在左子树的位置还是右子树的位置,接着循环到叶子节点进行添加
图解 :

代码实现:

public boolean insert(int val){
        //1.判断是否为空
        if(root == null){
            root = new TreeNode(val);
            return true;
        }
        //2.cur指向当前节点
        //preCur指向cur的上一个节点
        TreeNode preCur = root;
        TreeNode cur = null;
        //3.当cur超出叶子节点后,那此时preCur就指向要插入的叶子节点
        while(preCur != null){
            //判断往左插入还是往右插入
            if(preCur.val < val){
                cur = preCur;//保留上一步
                preCur = preCur.right;//往右走
            }
            else if(preCur.val > val){
                cur = preCur;//保留上一步
                preCur = preCur.left;//往左走
            }
            else{
                return false;//二叉搜索树中没有相等的值,如果相等就return false
            }
        }
        //4.while循环结束此时curPre成为了叶子结点,tmpNext已经成为了null
        //5.看看在比较进行插入
        if(cur.val < val){
            cur.right = new TreeNode(val);
        }else{
            cur.left = new TreeNode(val);
        }
        return true;
    }

实现二叉搜索树的查找方法 

先讲解思路,再进行图解,最后实现代码

思路:搜索的话其实在添加中已经实现过了,来走一遍
1.先判断二叉树是否为空,如果为空直接false
2.不为空,就从跟节点不断去比较大小,如果找到了就返回true,如果cur引用(指向当前节点)不断比较,超过了叶子节点(也就是cur指向空),那就说明没找到,返回false。

 代码实现:

public boolean search(int val){
        //1.判断是否为空
        if(root == null){
            return false;
        }
        //2.cur从根节点开始不断指向当前要比较的节点
        TreeNode cur = root;
        //3.cur不为空时,也说明还在寻找
        while(cur != null){
            //与当前节点进行比较
            if(cur.val < val){//val值大,cur就往右边走
                cur = cur.right;
            }
            else if(cur.val > val){//val值小,cur就往左边走
                cur = cur.left;
            }
            else//值相同,就返回true
            {
                return true;
            }
        }
        //能从while跳出来就说明cur此时为空了,也就没找到
        return false;
    }

实现二叉搜索树的删除方法

先讲解思路,再进行图解,最后实现代码

思路:删除比较麻烦一点,要分情况。
1.树为空,无法删除,返回false
2.先遍历寻找到要删除的节点
3.分情况删除节点
a.1删除节点的左子树为null
        a.1.1删除节点为根节点
        a.1.2删除节点为根节点的右子树
        a.1.3删除节点为根节点的左子树 

a.2删除节点的右子树为null
        a.2.1删除节点为根节点
        a.2.2删除节点为根节点的右子树
        a.2.3删除节点为根节点的左子树 

a.3删除节点的左右子树都不为null
        此时删除解节点的左右子树都不为空,我们需要采取一种替换法的方式
        简单来说:
        1.就是在被删节点的右子树中找最小值,通过最小值来覆盖要删除的节点,接着删除右子树中的最小值即可。
        2.同理,也可以在被删节点的左子树中找最大值,通过最大值来覆盖要删除的节点,接着删除左子树中的最大值即可。

我的实现:我选择的是第1中方式,在右子树中找最小值。

图解替换法:

 

a.1图解

a.2图解
 a.3替换法代码
 

public boolean remove(int val){
        //1.树为空,直接return false
        if(root == null){
            return false;
        }
        //2.先循环找到要删除的元素
        TreeNode cur = root;
        TreeNode curPre = null;
        while(cur != null){
            if(cur.val < val){
                //右侧找
                curPre = cur;
                cur = cur.right;
            }else if(cur.val > val){
                //左侧找
                curPre = cur;
                cur = cur.left;
            }else{
                //找到了,删除节点
                removeNode(curPre,cur);
                return true;
            }
        }
        return false;//没找到该节点
    }

private void removeNode(TreeNode parent,TreeNode tmp){//parent就是curPre  tmp就是cur
        //3.分情况
        // a.1被删节点的左子树为null
        if(tmp.left == null){
            //a.1.1删除节点为根节点
            if(tmp == root){
                parent = tmp.right;
            //a.1.2删除节点为根节点的右子树
            }else if(parent.right == tmp){
                parent.right = tmp.right;
            //a.1.3删除节点为根节点的左子树
            }else{
                parent.left = tmp.right;
            }

            //a.2别删节点的右侧为null
        }else if(tmp.right == null){
            //a.2.1删除节点为根节点
                if(tmp == root){
                    parent = tmp.left;
                //a.1.2删除节点为根节点的右子树
                }else if(parent.right == tmp){
                    parent.right = tmp.left;
                //a.1.3删除节点为根节点的左子树
                }else{
                    parent.left = tmp.left;
                }

        //a.3删除节点的左右子树都不为null,我使用被删节点的右子树中找最小值
        }else{
            TreeNode curParent = tmp;//记录cur的前一个
            TreeNode cur = tmp.right;//右子树找Min
            //被删节点的右子树下的左子树如果存在,那最小值肯定就在左子树
            while(cur.left != null){
                curParent = cur;
                cur = cur.left;
            }
            //此时有两种情况,一种压根没进while(无左子树),一种是进了(有左子树)
            //找到最小值并覆盖被删节点的值
            tmp.val = cur.val;
            //连接跳过最小值
            if(cur == curParent.left) {//有左子树
                curParent.left = cur.right;//此时cur是最小,连接cur的右子树
            }else {//无左子树
                curParent.right = cur.right;
            }
        }
    }

附带java代码



/**
 * 二叉搜索树:左子树的值都小于根节点的值,右子树的值都大于根节点的值
 * 平衡二叉树(AVL): 左子树和右子树的最大高度差小于或等于1,并且是一颗二叉搜索树
 */


/**
 * 实现二叉搜索树的基本功能:添加,删除,搜索
 */
class TreeNode{
    public int val;
    public TreeNode left;
    public TreeNode right;

    public TreeNode(int val) {
        this.val = val;
    }
}
public class BinarySearchTreeTest {
    public TreeNode root;


    private void removeNode(TreeNode parent,TreeNode tmp){//parent就是curPre  tmp就是cur
        //3.分情况
        // a.1被删节点的左子树为null
        if(tmp.left == null){
            //a.1.1删除节点为根节点
            if(tmp == root){
                parent = tmp.right;
            //a.1.2删除节点为根节点的右子树
            }else if(parent.right == tmp){
                parent.right = tmp.right;
            //a.1.3删除节点为根节点的左子树
            }else{
                parent.left = tmp.right;
            }

            //a.2别删节点的右侧为null
        }else if(tmp.right == null){
            //a.2.1删除节点为根节点
                if(tmp == root){
                    parent = tmp.left;
                //a.1.2删除节点为根节点的右子树
                }else if(parent.right == tmp){
                    parent.right = tmp.left;
                //a.1.3删除节点为根节点的左子树
                }else{
                    parent.left = tmp.left;
                }

        //a.3删除节点的左右子树都不为null,我使用被删节点的右子树中找最小值
        }else{
            TreeNode curParent = tmp;//记录cur的前一个
            TreeNode cur = tmp.right;//右子树找Min
            //被删节点的右子树下的左子树如果存在,那最小值肯定就在左子树
            while(cur.left != null){
                curParent = cur;
                cur = cur.left;
            }
            //此时有两种情况,一种压根没进while(无左子树),一种是进了(有左子树)
            //找到最小值并覆盖被删节点的值
            tmp.val = cur.val;
            //连接跳过最小值
            if(cur == curParent.left) {//有左子树
                curParent.left = cur.right;//此时cur是最小,连接cur的右子树
            }else {//无左子树
                curParent.right = cur.right;
            }
        }
    }

    /**
     * 使用替换法找到替换节点
     * @param val
     */
    public boolean remove(int val){
        //1.树为空,直接return false
        if(root == null){
            return false;
        }
        //2.先循环找到要删除的元素
        TreeNode cur = root;
        TreeNode curPre = null;
        while(cur != null){
            if(cur.val < val){
                //右侧找
                curPre = cur;
                cur = cur.right;
            }else if(cur.val > val){
                //左侧找
                curPre = cur;
                cur = cur.left;
            }else{
                //找到了,删除节点
                removeNode(curPre,cur);
                return true;
            }
        }
        return false;//没找到该节点
    }

    //查找
    public boolean search(int val){
        //1.判断是否为空
        if(root == null){
            return false;
        }
        //2.cur从根节点开始不断指向当前要比较的节点
        TreeNode cur = root;
        //3.cur不为空时,也说明还在寻找
        while(cur != null){
            //与当前节点进行比较
            if(cur.val < val){//val值大,cur就往右边走
                cur = cur.right;
            }
            else if(cur.val > val){//val值小,cur就往左边走
                cur = cur.left;
            }
            else//值相同,就返回true
            {
                return true;
            }
        }
        //能从while跳出来就说明cur此时为空了,也就没找到
        return false;
    }

    
    
    //添加方法
    public boolean insert(int val){
        //1.判断是否为空
        if(root == null){
            root = new TreeNode(val);
            return true;
        }
        //2.cur指向当前节点
        //preCur指向cur的上一个节点
        TreeNode preCur = root;
        TreeNode cur = null;
        //3.当cur超出叶子节点后,那此时preCur就指向要插入的叶子节点
        while(preCur != null){
            //判断往左插入还是往右插入
            if(preCur.val < val){
                cur = preCur;//保留上一步
                preCur = preCur.right;//往右走
            }
            else if(preCur.val > val){
                cur = preCur;//保留上一步
                preCur = preCur.left;//往左走
            }
            else{
                return false;//二叉搜索树中没有相等的值,如果相等就return false
            }
        }
        //4.while循环结束此时curPre成为了叶子结点,tmpNext已经成为了null
        //5.看看在比较进行插入
        if(cur.val < val){
            cur.right = new TreeNode(val);
        }else{
            cur.left = new TreeNode(val);
        }
        return true;
    }

    //先序遍历
    public void preOrder(TreeNode root) {
        if(root == null) return;
        System.out.print(root.val+" ");
        preOrder(root.left);
        preOrder(root.right);
    }

    //中序遍历
    public void inOrder(TreeNode root){
        if(root == null)
            return;
        inOrder(root.left);
        System.out.print(root.val+" ");
        inOrder(root.right);
    }

    public static void main(String[] args) {
        BinarySearchTreeTest testBinarySearchTree = new BinarySearchTreeTest();
        testBinarySearchTree.insert(13);
        testBinarySearchTree.insert(4);
        testBinarySearchTree.insert(17);
        testBinarySearchTree.insert(5);

        testBinarySearchTree.inOrder(testBinarySearchTree.root);
        System.out.println();
        testBinarySearchTree.preOrder(testBinarySearchTree.root);
        System.out.println();

        System.out.println(testBinarySearchTree.search(1));
        System.out.println(testBinarySearchTree.search(4));
        System.out.println(testBinarySearchTree.search(14));
        System.out.println(testBinarySearchTree.search(17));

        System.out.println("==========================================");
        testBinarySearchTree.remove(13);
        testBinarySearchTree.inOrder(testBinarySearchTree.root);
        System.out.println();
        testBinarySearchTree.preOrder(testBinarySearchTree.root);



    }
}

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值