二叉搜索树(binary search tree)

使用场景

  • 用作系统中的多级索引,实现高效的查找、插入、删除操作。

  • 作为某些搜索算法的底层数据结构。

  • 用于存储数据流,以保持其有序状态。

特点

1.对于根节点满足:任意左子树节点<跟节点<任意右子树节点

2.对于任意节点也满足1

查找操作

和二分查找法的工作原理一致,循环次数最多为树的高度,当树是平衡的话,它的查找时间复杂度为O(logn)

1.让一个指针root指向根节点

2.让查找袁术和根节点比大小

3.若比根节点大在右子树找,若比根节点小则在左子树找

/* 查找节点 */
TreeNode search(int num) {
    TreeNode cur = root;
    // 循环查找,越过叶节点后跳出
    while (cur != null) {
        // 目标节点在 cur 的右子树中
        if (cur.val < num)
            cur = cur.right;
        // 目标节点在 cur 的左子树中
        else if (cur.val > num)
            cur = cur.left;
        // 找到目标节点,跳出循环
        else
            break;
    }
    // 返回目标节点
    return cur;
}

插入操作

1.查询插入位置,从根节点出发,根据当前节点和插入num的大小判断在左右子树,直到越过叶子节点跳出循环,(查询到None)

2.在该位置插入新初始化节点

在这里我们用到pre来存储当前位置的父节点,方便初始化

当插入节点的值与当前节点的值相同时,直接返回,不进行插入操作(二叉搜索树不允许右相同值的节点出现)

时间复杂度O(logn)

/* 插入节点 */
void insert(int num) {
    // 若树为空,则初始化根节点
    if (root == null) {
        root = new TreeNode(num);
        return;
    }
    TreeNode cur = root, pre = null;
    // 循环查找,越过叶节点后跳出
    while (cur != null) {
        // 找到重复节点,直接返回
        if (cur.val == num)
            return;
        pre = cur;
        // 插入位置在 cur 的右子树中
        if (cur.val < num)
            cur = cur.right;
        // 插入位置在 cur 的左子树中
        else
            cur = cur.left;
    }
    // 插入节点
    TreeNode node = new TreeNode(num);
    if (pre.val < num)
        pre.right = node;
    else
        pre.left = node;
}

删除操作

当要删除的节点的度为0的时候,我们可以直接将其删除,不影响二叉搜索树的性质

当要删除的节点的度为1的时候,说明有一个子节点,将其子节点代替该节点即可

当要删除的节点的度为2的时候,可以把它替换为左子树的最大值,也可以替换成右子树的最小值来实现左子树<该节点<右子树
因为中序遍历在遍历完该节点后要编列右子树最小节点,所以我们选择使用右子树最小节点替换

1.找到要删除节点的右子树最小节点tmp,也就是中序遍历的下一个节点

2用tmp覆盖要删除节点,递归删除节点tmp

代码实现 

/* 删除节点 */
void remove(int num) {
    // 若树为空,直接提前返回
    if (root == null)
        return;
    TreeNode cur = root, pre = null;
    // 循环查找,越过叶节点后跳出
    while (cur != null) {
        // 找到待删除节点,跳出循环
        if (cur.val == num)
            break;
        pre = cur;
        // 待删除节点在 cur 的右子树中
        if (cur.val < num)
            cur = cur.right;
        // 待删除节点在 cur 的左子树中
        else
            cur = cur.left;
    }
    // 若无待删除节点,则直接返回
    if (cur == null)
        return;
    // 子节点数量 = 0 or 1
    if (cur.left == null || cur.right == null) {
        // 当子节点数量 = 0 / 1 时, child = null / 该子节点
        TreeNode child = cur.left != null ? cur.left : cur.right;
        // 删除节点 cur
        if (cur != root) {
            if (pre.left == cur)
                pre.left = child;
            else
                pre.right = child;
        } else {
            // 若删除节点为根节点,则重新指定根节点
            root = child;
        }
    }
    // 子节点数量 = 2
    else {
        // 获取中序遍历中 cur 的下一个节点
        TreeNode tmp = cur.right;
        while (tmp.left != null) {
            tmp = tmp.left;
        }
        // 递归删除节点 tmp
        remove(tmp.val);
        // 用 tmp 覆盖 cur
        cur.val = tmp.val;
    }
}

中序遍历有序

利用二叉搜索树的性质左<中<右,以及中序遍历左-->中-->右的性质,在二叉搜索树中只用O(n)的时间复杂度就可以得到有序数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值