二叉搜索树

二叉搜索树

今天简单的说一下二叉搜索树,为什么叫做二叉搜索树呢?从名字我们就能看出来,用它进行查询操作会很方便。
二叉搜索树的一些特性:
1:二叉搜索树的中序遍历是一个有序的序列
2:二叉搜索树也可以是一棵空树
3:若它的左子树不为空,那么它的左子树上的所有节点的值都小于根节点的值。
4:若它的右子树不为空,那么它的右子树上的所有节点的值都大于根节点的值。
5:二叉搜索树的左右子树也是二叉搜索树。
6:二叉搜索树中最左侧的节点一定是最小的节点,最右侧的节点一定是最大的节点。

关于二叉搜索树的一些操作

我们知道可以在二叉搜索树中查找元素,插入元素,删除元素等等。
我认为,一切基于查询的基础上进行一些操作。
给张图,可能看着更好理解,哈哈。
在这里插入图片描述
下面是查询元素的代码

 public static class Node{
        private Node left;
        private Node right;
        int val;
        public Node(int val){
            this.val=val;
        }
    }
    public Node root=null;
    //是否包含给定值
    public boolean contains(int val){
        if(root==null){
            throw new IllegalArgumentException();
        }
        Node cur=root;
        while (cur!=null){
            if (cur.val==val){
                return true;
            }else if (cur.val>val){
                cur=cur.left;
            }else {
                cur=cur.right;
            }
        }
        return false;
    }

用到了静态内部类来创建一个节点对象,是不是很方便啊,哈哈哈。
下面是插入操作,插入元素在查询的基础上增加了一点代码,但是还是大同小异,但是要注意我们要用一个节点来保存待插入节点的前驱,意思不太准确,学过单链表就应该懂我的意思
下面是插入的代码:

 //插入,要知道待插入节点的父节点
    public boolean put(int val){
        if(root==null){
            throw new IllegalArgumentException();
        }
        Node cur = root;
        Node parent=null;
        while(cur!=null){
            parent=cur;
            if(cur.val==val){
                return false;
            }else if (cur.val>val){
                cur=cur.left;
            }else {
                cur=cur.right;
            }
        }
        //要插入的节点
        cur=new Node(val);
        if(parent.val>val){
            parent.left=cur;
        }
        else {
            parent.right=cur;
        }
        return true;
    }

删除就相对麻烦了点,关键是分的情况太多了,话不多说,上代码,我在代码里面都注释了。

 public boolean remove(int val){
        //如果root为空
        if(null==root){
            throw new IllegalArgumentException();
        }
        //遍历搜索树,找到与val值相等的节点结束循环
        //用一个节点保存待删除节点的父节点
        Node cur=root;
        Node parent=null;
        while (cur!=null){
            if(val>cur.val){
                parent=cur;
                cur=cur.right;
            }else if (val<cur.val){
                parent=cur;
                cur=cur.left;
            }else {
                break;
            }
        }
        if(cur==null){
            return false;
        }
        //已经找到待删除节点,现在分情况
        //1:cur只有左孩子
        if(cur.right==null){
            //只有左孩子并且cur为头结点
            if(parent==null){
                root=cur.left;
                return true;
            }else {
                //只有左孩子cur不是头结点
                parent.left=cur.left;
                return true;
            }
        }
        //2:cur只有右孩子
        if(cur.left==null){
            //只有右孩子并且cur为头结点
            if(parent==null){
                root=cur.right;
                return true;
            }else {
                //只有右孩子cur不是头结点
                parent.right=cur.right;
                return true;
            }
        }
        //3:cur左右孩子均存在
        //不能直接删除,在它的子树中找一个替代节点
        //左子树:找左子树中最大的节点(最右侧节点)
        //右子树:找右子树中最小的节点(最左侧节点)
        Node del=cur.right;
        parent=cur;
        while (del.left!=null){
            parent=del;
            del=del.left;
        }
        //替代节点找到
        cur.val=del.val;
        //删除这个节点,相当于替代节点到了cur的位置
        //再把最下面的替代节点删掉,转换思维,就是删掉了cur
        if(del==parent.left){
            parent.left=del.right;
            return true;
        }else {
            parent.right=del.right;
            return true;
        }
    }

看了这代码是不是想打人,淡定,其实我和你是一样的心情,可能有更好的方式,希望大家发现错误指出来,一起学习进步,奥利给。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值