首页 > 其他分享 >二叉搜索树

二叉搜索树

时间:2023-06-26 20:33:20浏览次数:35  
标签:right TreeNode 二叉 搜索 return root 节点 left

二叉搜索树

二叉搜索树(Binary Search Tree,BST)是指一颗空树或者有下列性质的二叉树:

  • 若任意节点的左子树不为空,那么左子树上所有节点的值均小于它的根节点的值;
  • 若任意节点的右子树不为空,那么右子树上所有节点的值均小于它的根节点的值;
  • 任意节点的左、右子树也分别为二叉搜索树;

二叉树的定义是从一个递归的角度来定义的,验证二叉树其实很简单,即中序遍历二叉树,节点的值从严格递增。换言之,二叉搜索树也可以定义成中序遍历时节点值严格递增的二叉树。

BST 的删除

对树的定义,我们采取 Leetcode 中的定义:

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode() :
        val(0), left(nullptr), right(nullptr) {
    }
    TreeNode(int x) :
        val(x), left(nullptr), right(nullptr) {
    }
    TreeNode(int x, TreeNode *left, TreeNode *right) :
        val(x), left(left), right(right) {
    }
};

首先,我们定义两个辅助函数 TreeNode *delMax(TreeNode *root, int key);TreeNode *delMin(TreeNode *root, int key);,分别表示删除二叉树中的值最大的节点和值最小的节点。还需要辅助函数 int getMin(TreeNode *root);int getMax(TreeNode *root)

getMingetMax 自不必多说,以 delMax 为例,都是利用递归进行处理,递归返回的是当前以 root 为根节点的树,删除了最大值之后的 root。递归终止条件即 root->right == nullptr,说明找到了树的最大值,此时返回 root->left。(以避免左子树不为空的情况,左子树为空则相当于返回了 nulltpr

int getMax(TreeNode *root) {
    if (root->right == nullptr) {
        return root->val;
    }
    return getMax(root->right);
}

int getMin(TreeNode *root) {
    // 不考虑空树的情况
    if (root->left == nullptr) {
        return root->val;
    }
    return getMin(root->left);
}
TreeNode *delMax(TreeNode *root) {
    if (root == nullptr) {
        return root;
    }
    if (root->right == nullptr) {
        return root->left;
    }
    root->right = delMax(root->right);
    return root;
}
TreeNode *delMin(TreeNode *root) {
    if (root == nullptr) {
        return root;
    }
    if (root->left == nullptr) {
        return root->right;
    }
    root->left = delMin(root->left);
    return root;
}

那么,有了这几个辅助函数之后,我们要如何处理 BST 的删除节点呢。还是递归进行处理,递归返回的是将以当前节点为根节点的树删除 key 对应节点之后的根节点 root

  • 如果 key 小于当前节点值,那么递归删除左子树;
  • 如果 key 大于当前节点值,那么递归删除右子树;
  • 如果 key 等于当前节点值,分两种情况讨论:
    • 如果当前节点没有右子节点,那么返回当前节点的左子节点,即 return root->left;,这样也能处理左子树也为空的情况;
    • 如果当前节点的右子树不为空,那么我们将当前节点的值替换为右子树的最小值 valval 相当于是满足 k > key 的最小的 k,然后对该右子树,执行 delMin

当然,碰到 key 等于当前节点值的情况时,我们考虑左子节点也是可以的,与考虑右子节点是对称的。

TreeNode *del(int key, TreeNode *root) {
    if (root == nullptr) {
        return nullptr;
    }
    if (key < root->val) {
        root->left = del(key, root->left);
    } else if (key > root->val) {
        root->right = del(key, root->right);
    } else {
        // root->val == key
        if (root->right == nullptr) { // 没有右子树
            return root->left;
        }
        root->val = getMin(root->right);
        root->right = delMin(root->right);
    }
    return root;
}

BST 的时间复杂度分析

我们知道,假设 BST 没有额外的限制,那么,最坏情况下,它可能退化成一个有序链表,此时插入和查找的时间复杂度为 $O(n)$。

而我们如果利用插入节点,从无到有构造一棵 BST,并且插入的节点的值都是随机的,那么这棵 BST 的最大深度是 $O(\log n)$ 的($n$ 为 BST 的节点数),即查找和插入的时间复杂度是 $O(\log n)$ 的。

但如果,我们除了执行随机节点的插入之外,还执行随机删除,那么 BST 的最大深度就会变成 $O(\sqrt n)$,即查找、插入、删除的时间复杂度变成了 $O(\sqrt n)$。

标签:right,TreeNode,二叉,搜索,return,root,节点,left
From: https://www.cnblogs.com/zwyyy456/p/17506647.html

相关文章

  • 图书搜索领域重大突破!用Apache SeaTunnel、Milvus和OpenAI提高书名相似度搜索精准度和
    作者|刘广东,ApacheSeaTunnelCommitter背景目前,现有的图书搜索解决方案(例如公共图书馆使用的解决方案)十分依赖于关键词匹配,而不是对书名实际内容的语义理解。因此会导致搜索结果并不能很好地满足我们的需求,甚至与我们期待的结果大相径庭。这是因为仅仅依靠关键词匹配是不够......
  • 搜索框 多个条件模糊查询
    1.利用逗号或者空格进行多个关键字的模糊查询把所有的空格装换成英文的逗号(首先要把相邻的多个空格转化为一个空格,中文的逗号转化为统一的英文逗号),$str=str_replace(",",",",$str);//装换字符$str=preg_replace('!\s+!','',$str);//相邻空格合并$s......
  • 代码随想录算法训练营第十七天| 654.最大二叉树 617.合并二叉树 700.二叉搜索树中
     654.最大二叉树 比较简单,直接上代码1TreeNode*constructMax_cursor(vector<int>&nums)2{3if(nums.size()==0)returnNULL;4//getMaxNum5intindex=0;6intmax_=INT_MIN;7for(inti=0;i<nums.size();i++)8......
  • 图文示例二叉树的编码实现过程
    前言在上一篇文章中,带大家一起学习认识了树型数据结构的定义和特点,并特别介绍了二叉树的遍历操作,分别有:前序遍历、中序遍历、后序遍历。前中后的核心区别是根据根节点在遍历过程中的位置决定的,即:根节点在最前面的称之为中序遍历,根节点在中间的称之为中序遍历,根节点在最后的称之为......
  • 算法——DFS、BFS、记忆回溯、记忆搜索
    回溯和深度优先搜索的区别回溯是一种更通用的算法。可以用于任何类型的结构,其中可以消除域的部分——无论它是否是逻辑树。深度优先搜索是与搜索树或图结构相关的特定回溯形式。它使用回溯作为其使用树的方法的一部分,但仅限于树/图结构。回溯和DFS之间的区别在于回溯处理隐......
  • 关于二叉树的操作
    树是数据结构中的重中之重,尤其以各类二叉树为学习的难点。在面试环节中,二叉树也是必考的模块。本文主要讲二叉树操作的相关知识,梳理面试常考的内容。一起来复习吧。 本篇针对面试中常见的二叉树操作作个总结:前序遍历,中序遍历,后序遍历;层次遍历;求树的结点数;求树的叶子数;求......
  • 二叉树-快排-leetcode912
    给你一个整数数组nums,请你将该数组升序排列。示例1:输入:nums=[5,2,3,1]输出:[1,2,3,5]示例2:输入:nums=[5,1,1,2,0,0]输出:[0,0,1,1,2,5]提示:1<=nums.length<=5*104-5*104<=nums[i]<=5*104思路:快排,或者叫前序二叉树,排序后端结果是一个二叉搜索树//lee......
  • 搜索引擎
    搜索引擎......
  • 树和二叉树详细讲解
    前言在上篇文章中,向大家介绍了线性数据结构中的栈、队列和串三种数据结构,相对来说比较简单,栈的特点是先进后出(FILO),队列的特点是先进先出(FIFO)。栈包含入栈和出栈两个操作,两个操作操作的都是栈顶元素;队列包含入队和出队两个操作,元素从队尾进入队列,需要时从队头取出元素。全......
  • 二叉树
    #include<stdio.h>#include<stdlib.h>#include<malloc.h>typedefstructBTNode{ chardata; structBTNode*lchild; structBTNode*rchild;}*BiTree;voidcreateBiTree(BiTree*t){//此处补充代码,输入二叉树的先序遍历序列建立二叉树 chars;......