二叉搜索树(BST)的基本操作详解(代码全,含测试用例)

目录

1.概念及其特性

2.基本操作

(1).查找

(2).插入

(3)删除

3.总结


1.概念及其特性

二叉搜索树:

1.是一个二叉树

2.每个节点中保存关键字(Key)

3.关键字需要具备比较能力

4.每个节点遵守:左子树的所有Key < 其key <右子树的所有Key

5.二叉树中不会出现相等的Key

6.二叉搜索树的中序遍历一定是有序的

2.基本操作

我们需要一个结点类和一个二叉搜索树类

结点类Node:

public class Node {
    public Integer key;
    public Node left;
    public Node right;

    public Node(Integer key) {
        this.key = key;
    }

    @Override
    public String toString() {
        return "Node{" +
                "key=" + key +
                '}';
    }
}

二叉搜索树类:

public class BST {
    private Node root;
}

(1).查找

1.方法体分析:

2.思路:

查找的时候,比当前节点小就往左走,比当前节点大就往右走,相等就退出,找到null也退出,具体代码如下:

public boolean search(Integer key){
    Node current = this.root;
    while (current != null){
        int cmp = key.compareTo(current.key);
        if (cmp == 0){
            return true;
        }else if (cmp < 0){
            current = current.left;
        }else {
            current = current.right;
        }
    }
    return false;
}

(2).插入

如果一个方法中需要用到对象,则这个方法一定是非静态的。

1.方法体分析:

2.代码思路:

和查找类似,设一个parent结点,维护其一直是cur的双亲结点,然后cur往下找,要是找到相等的结点,则抛出异常;找到空,就可以进行插入(要根据cmp判断一下是插到左边还是右边),具体代码如下:

public void insert(Integer key) {
    if (root == null) {
        root = new Node(key);
        return;
    }

    // 始终保持 parent 就是 current 的双亲节点
    Node parent = null;
    Node current = root;

    int cmp = 0;
    while (current != null) {
        cmp = key.compareTo(current.key);
        if (cmp == 0) {
            throw new RuntimeException("BST 中不允许出现相同的 key");
        } else if (cmp < 0) {
            parent = current;
            current = current.left;
        } else {
            parent = current;
            current = current.right;
        }
    }

    // current 一定 null。
    // parent 就是要插入新节点的双亲节点
    Node node = new Node(key);
    if (cmp < 0) {
        parent.left = node;
    } else {
        parent.right = node;
    }
}

(3).删除

1.分析

2.代码思路

1).查找包含key的结点,记作node。node的父节点记作parent

2).判断

情况一:node.left == null && node.right == null

情况二:node.left != null && node.right == null

情况三:和情况二类似

情况四:替换法(选择左子树中最大的一个节点(节点的right == null,记为ghost))

node是要删除的那个节点,ghost是左子树中最大的那个节点

 具体代码如下:

public boolean remove(Integer key) {
    // 1. 查找要删除的 key 所在的节点,记作 node。node 的双亲节点,记作 parent
    Node parent = null;
    Node current = root;

    while (current != null) {
        int cmp = key.compareTo(current.key);
        if (cmp == 0) {
            removeInternal(current, parent);
            return true;
        } else if (cmp < 0) {
            parent = current;
            current = current.left;
        } else {
            parent = current;
            current = current.right;
        }
    }

    return false;
}

private void removeInternal(Node node, Node parent) {
    if (node.left == null && node.right == null) {
        if (node == root) {
            root = null;
        } else if (node == parent.left) {
            parent.left = null;
        } else {
            parent.right = null;
        }
    } else if (node.left != null && node.right == null) {
        if (node == root) {
            root = node.left;
        } else if (node == parent.left) {
            parent.left = node.left;
        } else {
            parent.right = node.left;
        }
    } else if (node.left == null && node.right != null) {
        if (node == root) {
            root = node.right;
        } else if (node == parent.left) {
            parent.left = node.right;
        } else {
            parent.right = node.right;
        }
    } else {
        // 使用替换法删除,使用 node 的左子树中的最大值所在的节点,记作 ghost。ghost 的双亲记作 ghostParent
        Node ghostParent = node;
        Node ghost = node.left;
        // 一路朝右查找,直到 ghost.right == null
        while (ghost.right != null) {
            ghostParent = ghost;
            ghost = ghost.right;
        }

        //这里的ghost一定没有右子树
        // 1. 替换
        node.key = ghost.key;
        // 2. 删除 ghost 节点(其右孩子一定是 null)
        if (node == ghostParent) {
            //删除点即为左子树最大点的双亲,只有这种情况,ghost才有可能为ghostParent的左子树
            //这种情况就是node的左孩子没有右孩子
            ghostParent.left = ghost.left;
        } else {
            //否则,ghost一定是ghostParent右子树
            //这种情况就是node的右孩子没有左孩子
            ghostParent.right = ghost.left;
        }
    }
}

3.总结

二叉搜索树

重要特点:中序是有序的!

操作:

1.插入/查找/删除

2.时间复杂度:最好和平均的:O(log(n))   最坏:O(n)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值