【树】二叉搜索树的汇总

二叉搜索树的概述

二叉搜索树(BST,Binary Search Tree),也称二叉排序树 或 二叉查找树。

二叉搜索树要么是棵空树,要么是棵满足下列性质的二叉树:

  1. 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  2. 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  3. 它的左、右子树也分别为二叉排序树。
  4. 没有键值相等的节点。

在这里插入图片描述

BST的实现

🎶树布局(节点)

	这里运用泛型,树节点只接受实现了Comparable接口的对象。包装类、String类、
自身创建的类对象等等。
public class BSTree<T extends Comparable<T>> {
    /**
     * BST的根节点
     */
    private BSTNode<T> root;
	
	......

	class BSTNode<T extends Comparable<T>> {
        T value;
        BSTNode<T> leftNode;
        BSTNode<T> rightNode;
        BSTNode<T> parentNode;

        public BSTNode(T value, BSTNode<T> leftNode, BSTNode<T> rightNode, BSTNode<T> parentNode) {
            this.value = value;
            this.leftNode = leftNode;
            this.rightNode = rightNode;
            this.parentNode = parentNode;
        }
    }
}

🎶插入

向二叉搜索树(BST)中插入结点,插入的节点是叶子节点(根据BST的性质,如果仍存在左右节点的话还会进行比较,直到比较结束最后进行插入)。

在这里插入图片描述

(后续的测试代码,树节点都是按这个来初始化的)

代码实现

	public void insert(T v){
        BSTNode<T> insertNode = new BSTNode<>(v,null,null,null);
        if (insertNode!=null) {
            insert(this,insertNode);
        }
    }

    /**
     * 插入某个节点
     * @param tst 根节点
     * @param insertNode 插入的节点
     */
    private void insert(BSTree<T> tst, BSTNode<T> insertNode){
        int cmpAns;
        BSTNode<T> moveNode = tst.root;
        BSTNode<T> preNode = null;
        while(moveNode!=null){
            preNode = moveNode;
            cmpAns = insertNode.value.compareTo(moveNode.value);
            if(cmpAns<0){
                moveNode = moveNode.leftNode;
            }else{
                moveNode = moveNode.rightNode;
            }
        }
        if(preNode==null){
            root = insertNode;
        }else{
            insertNode.parentNode = preNode;
            int comAns = insertNode.value.compareTo(preNode.value);
            if (comAns < 0) {
                preNode.leftNode = insertNode;
            }else{
                preNode.rightNode = insertNode;
            }
        }
    }

🎶遍历

由于二叉搜索树也称二叉排序树,这只使用中序遍历,使得最后结果序列是有序的。

利用递归的方式二叉搜索树进行中序遍历:

    /**
     * 中序遍历
     * @return 有序节点序列
     */
    public List<T> inOrder(){
        List<T> bstNodes = new ArrayList<>();
        inOrder(root,bstNodes);
        return bstNodes;
    }

    private void inOrder(BSTNode<T> root, List<T> bstNodes) {
        if(root!=null){
            inOrder(root.leftNode,bstNodes);
            bstNodes.add(root.value);
            inOrder(root.rightNode,bstNodes);
        }
    }

在这里插入图片描述

🎶查找

利用递归或者非递归的方式进行查找,没查找到返回null,查找到了返回对应的节点。
(递归和非递归实现也没啥难,区别也不大,这里只用递归实现一下)

递归实现代码:

    /**
     * 二叉搜索树的查找操作
     * @param root 移动节点,被查找对象
     * @param v 查找值
     * @return
     */
    private BSTNode<T> search(BSTNode<T> root, T v) {
        if(root!=null) {
            int cmp = v.compareTo(root.value);
            if(cmp<0){
                return search(root.leftNode,v);
            }else if(cmp>0){
                return search(root.rightNode,v);
            }else{
                return root;
            }
        }
        return null;
    }

测试:

在这里插入图片描述

🎶删除

删除BST 的节点,该节点类型无非分为三类:
1. 为叶子节点,无左右子孩子;
2. 有左孩子或者右孩子;
3. 左右孩子都有。
咱逐一击破即可,注意删除节点的父节点和孩子节点的更换,
对于左右子孩子都存在的节点,使用值传递进行假删除。
public BSTNode<T> findMaxNode(BSTNode<T> node){
        BSTNode<T> target = node;
        while(target.rightNode!=null){
            target = target.rightNode;
        }
        return target;
    }

    public void remove(T v){
        BSTNode<T> s, node;
        if((s=this.search(v))!=null) {
            if((node=remove(this,s))!=null) {
                node = null;
            }
        }
    }

    private BSTNode<T> remove(BSTree<T> tbsTree, BSTNode<T> s) {
        BSTNode<T> node = null;
        if(s.leftNode==null&&s.rightNode==null){// 情况1:s为叶子节点
            if(s.parentNode!=null&&s.parentNode.leftNode!=null&&s.parentNode.leftNode.value==s.value){
                s.parentNode.leftNode = null;
            }else if(s.parentNode!=null&&s.parentNode.rightNode!=null&&s.parentNode.rightNode.value==s.value){
                s.parentNode.rightNode = null;
            }
            return s;
        }else if(s.leftNode!=null&&s.rightNode!=null){// 情况2:s有左右子节点
            node = findMaxNode(s.leftNode);
            remove(this,node);// 这查到的最后是个叶子节点,更新父节点子节点。
            s.value = node.value;
        }else{// 情况3:s有左或者右子节点
            if(s.parentNode==null) {
                this.root = (s.leftNode == null) ? s.rightNode : s.leftNode;
            }else if(s.rightNode==null){
                if (s.parentNode.leftNode.value==s.value) {
                    s.parentNode.leftNode = s.leftNode;
                }else{
                    s.parentNode.rightNode = s.leftNode;
                }
            }else if(s.leftNode==null){
                if (s.parentNode.leftNode.value==s.value) {
                    s.parentNode.leftNode = s.rightNode;
                }else{
                    s.parentNode.rightNode = s.rightNode;
                }
            }
            node = s;
        }
        return node;
    }

测试:

在这里插入图片描述

BSF相关题目

BST 相关题目

通过刷算法题,可以对BSF 性质更加了解,对遍历操作更加熟悉。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

假正经的小柴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值