当前位置: 首页 > news >正文

初级数据结构——二叉搜索树

目录

  • 前言
  • 一、定义
  • 二、基本操作
  • 三、时间复杂度分析
  • 四、变体
  • 五、动态图解
  • 六、代码模版
  • 七、经典例题
    • [1.——700. 二叉搜索树中的搜索](https://leetcode.cn/problems/search-in-a-binary-search-tree/)
      • 代码题解
    • [2.——938. 二叉搜索树的范围和](https://leetcode.cn/problems/range-sum-of-bst/)
      • 代码题解
    • [3.——98. 验证二叉搜索树](https://leetcode.cn/problems/validate-binary-search-tree/)
      • 代码题解
  • 八、总结
  • 结语

前言

这一期我们一起来学习二叉搜索树。二叉搜索树(Binary Search Tree, BST)是一种重要的数据结构,在计算机科学中广泛应用于查找、插入和删除操作。以下是对二叉搜索树的基本分析,包括其定义、性质、操作的时间复杂度以及一些变体。

一、定义

二叉搜索树是一种二叉树,其中每个节点包含一个键值,且满足以下性质:

左子树性质:左子树中所有节点的键值都小于根节点的键值。
右子树性质:右子树中所有节点的键值都大于根节点的键值。
递归性质:左子树和右子树本身也是二叉搜索树。

二、基本操作

1.查找(Search)
算法:从根节点开始,如果目标键值小于当前节点的键值,则递归地在左子树中查找;如果目标键值大于当前节点的键值,则递归地在右子树中查找;如果找到目标键值,则返回该节点。
时间复杂度:在最坏情况下(树退化为链表),时间复杂度为 O(n);在最优情况下(树是平衡的),时间复杂度为 O(logn)。

2.插入(Insert)
算法:从根节点开始,找到合适的位置插入新节点。如果目标键值小于当前节点的键值,则递归地在左子树中查找插入位置;如果目标键值大于当前节点的键值,则递归地在右子树中查找插入位置;如果目标键值已经存在,则根据具体需求更新节点(例如,更新节点的值或不做任何操作)。
时间复杂度:与查找操作类似,最坏情况下为 O(n),最优情况下为 O(logn)。

3.删除(Delete)
算法:找到要删除的节点,然后分三种情况处理:
叶子节点:直接删除。
只有一个子节点:用其子节点替代被删除节点。
有两个子节点:找到该节点的中序后继(或中序前驱),用其值替代被删除节点的值,然后递归删除中序后继(或中序前驱)。
时间复杂度:最坏情况下为 O(n),最优情况下为 O(logn)。

三、时间复杂度分析

二叉搜索树的时间复杂度依赖于树的高度。在最坏情况下(树退化为链表),树的高度为 n,因此各种操作的时间复杂度均为 O(n)。然而,在最优情况下(树是平衡的),树的高度为 logn,因此各种操作的时间复杂度均为 O(logn)。

四、变体

为了改善二叉搜索树在最坏情况下的性能,人们提出了多种变体:

平衡二叉搜索树(Balanced BST):如AVL树、红黑树等,通过维护树的平衡来确保操作的时间复杂度始终为 O(logn)。
B树(B-Tree):一种自平衡的树,能够保持数据有序,其设计目的是减少磁盘I/O操作,广泛应用于数据库和文件系统。
伸展树(Splay Tree):在每次查找操作后,通过一系列旋转操作将查找路径上的节点重新组织成一条链,使得下次查找更加高效。

五、动态图解

元素查找:
在这里插入图片描述
元素插入:
在这里插入图片描述

元素删除:
元素

中序遍历
在这里插入图片描述

六、代码模版

#include<iostream>
using namespace std;template<typename T>
struct TreeNode {T val;TreeNode* left;TreeNode* right;TreeNode(T x):val(x),left(NULL),right(NULL){}TreeNode():val(0),left(NULL),right(NULL){}
};template<typename T>
class BinarySearchTree {
private:TreeNode<T>* root;TreeNode<T>* insertNode(TreeNode<T>* node, T val);TreeNode<T>* removeNode(TreeNode<T>* node, T val);bool searchNode(TreeNode<T>* node, T val);void inOrder(TreeNode<T>* node);
public:BinarySearchTree():root(NULL){}~BinarySearchTree();void insert(T val) {root = insertNode(root, val);}void remove(T val) {root = removeNode(root, val);}bool search(T val) {return searchNode(root, val);}void inOrderTraversal() {inOrder(root);cout << endl;}
};template<typename T>
BinarySearchTree<T>::~BinarySearchTree() {while (root) {remove(root->val);//每次都把root节点删除,每次删除都产生新的root节点}
}template<typename T>
TreeNode<T>* BinarySearchTree<T>::insertNode(TreeNode<T>* node, T val) {if (!node) {return new TreeNode<T>(val);//递归出口,该节点为空时就说明插入到当前位置,定义新的变量接收val}if (node->val > val) {node->left = insertNode(node->left, val);}else if (node->val < val) {node->right = insertNode(node->right, val);}return node;//说明当前节点与插入节点的值一致返回该节点即可
}template<typename T>
TreeNode<T>* BinarySearchTree<T>::removeNode(TreeNode<T>* node, T val) {if (!node)return NULL;//递归出口,如果找完了整棵树都没找到该值就返回NULLif (node->val > val) node->left = removeNode(node->left, val);else if (node->val < val)node->right = removeNode(node->right, val);else {//该节点的值等于要删除节点的值一致就说明找到了if (node->left == NULL && node->right == NULL) {//如果该节点为叶子结点,接直接删除该节点就行delete node;return NULL;//因为删除了该节点所以它就为空了返回即可}else if (node->left == NULL) {//要删除的节点只有右节点TreeNode<T>* rightChild = node->right;//定义一个变量储存该节点右节点的树delete node;return rightChild;}else if (node->right == NULL) {//与上同理TreeNode<T>* leftChild = node->left;delete node;return leftChild;}else {//如果左右节点都有TreeNode<T>* replacement = node->right;//从右子树中找值最小的节点while (replacement->left) {replacement = replacement->left;}node->val = replacement->val;//找到之后赋给该节点node->right = removeNode(node->right, replacement->val);//最后在删除最小值的节点}}return node;
}template<typename T>
bool BinarySearchTree<T>::searchNode(TreeNode<T>* node, T val) {if (!node)return false;//递归出口如果找完了整棵树都没找到该值就返回falseif (val < node->val) {//递归查找如果要查找的值小于当前节点那么就继续递归找左节点return searchNode(node->left, val);}else if (val > node->val) return searchNode(node->right, val);//与上同理return true;
}template<typename T>
void BinarySearchTree<T>::inOrder(TreeNode<T>* node) {if (node) {//中序遍历inOrder(node->left);cout << node->val << ',';inOrder(node->right);}
}int main() {BinarySearchTree<int> bst;bst.insert(30);bst.insert(10);bst.insert(20);bst.insert(40);bst.insert(90);bst.insert(69);bst.inOrderTraversal();//中序遍历为递增有序的数列bst.remove(40);bst.inOrderTraversal();return 0;
}

七、经典例题

1.——700. 二叉搜索树中的搜索

(蓝色字体可以点进去看原题)

代码题解

/*** Definition for a binary tree node.* 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) {}* };*/
class Solution {
public:TreeNode* searchBST(TreeNode* root, int val) {if(root==NULL)return NULL;if(val>root->val)return searchBST(root->right,val);else if(root->val>val)return searchBST(root->left,val);return root;}
};

2.——938. 二叉搜索树的范围和

代码题解

/*** Definition for a binary tree node.* 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) {}* };*/
class Solution {
public:int rangeSumBST(TreeNode* root, int low, int high) {if(root==NULL)return 0;int sum=0;if(root->val>=low&&root->val<=high){sum+=root->val;}sum+=rangeSumBST(root->left,low,high);sum+=rangeSumBST(root->right,low,high);return sum;}
};

3.——98. 验证二叉搜索树

代码题解

/*** Definition for a binary tree node.* 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) {}* };*/
class Solution {vector<int> ret;void inOrder(TreeNode*root){if(root){inOrder(root->left);ret.push_back(root->val);inOrder(root->right);}}
public:bool isValidBST(TreeNode* root) {ret.clear();inOrder(root);//中序遍历之后就是递增的数列for(int i=1;i<ret.size();i++){if(ret[i]<=ret[i-1])return false;}return true;}
};

八、总结

二叉搜索树是一种简单而有效的数据结构,适用于许多查找、插入和删除操作。然而,其性能受树的高度影响,因此在最坏情况下可能退化为链表。为了克服这一缺点,可以使用平衡二叉搜索树等变体来确保操作的时间复杂度始终为 O(logn)。

结语

下期我会更新二叉搜索树的题库一共十多道,希望大家看完之后能去多多刷题巩固和运用知识点,敬请期待下期文章。

在这里插入图片描述

相信大家通过本期学习初步了解二叉树,下期作品我会更新二叉树的十几道题库,我们下期一起学习二叉树的实战应用。
在这里插入图片描述

相关文章:

初级数据结构——二叉搜索树

目录 前言一、定义二、基本操作三、时间复杂度分析四、变体五、动态图解六、代码模版七、经典例题[1.——700. 二叉搜索树中的搜索](https://leetcode.cn/problems/search-in-a-binary-search-tree/)代码题解 [2.——938. 二叉搜索树的范围和](https://leetcode.cn/problems/ra…...

C++设计模式之组合模式中如何实现同一层部件的有序性

在组合模式中&#xff0c;为了实现同一层上部件的有序性&#xff0c;可以采取以下几种设计方法&#xff1a; 1. 使用有序集合 使用有序集合&#xff08;如 std::list、std::vector 或其他有序容器&#xff09;来存储和管理子部件。这种方法可以确保子部件按照特定顺序排列&am…...

duxapp RN 端使用AppUpgrade 进行版本更新

版本更新包含了组件和工具的组合 注册 下面这是 duxcms 入口文件检查更新的注册方法&#xff0c;注册的同时会检查更新 import {request,updateApp,userConfig } from ./utils// 检查app更新 setTimeout(async () > {if (process.env.TARO_ENV rn) {// eslint-disable-n…...

【计网】自定义序列化反序列化(三) —— 实现网络版计算器【下】

&#x1f30e;实现网络版计算器【下】 本次序列化与反序列化所用到的代码&#xff0c;Tcp服务自定义序列化反序列化实现网络版计算器。 文章目录&#xff1a; 实实现网络版计算器【下】 客户端实现     基于守护进程的改写 &#x1f680;客户端实现 在这之前&#xff0c…...

神经网络中的优化方法(一)

目录 摘要Abstract1. 与纯优化的区别1.1 经验风险最小化1.2 代理损失函数1.3 批量算法和小批量算法 2. 神经网络中优化的挑战2.1 病态2.2 局部极小值2.3 高原、鞍点和其他平坦区域2.4 悬崖和梯度爆炸2.5 长期依赖2.6 非精确梯度2.7 局部和全局结构间的弱对应 3. 基本算法3.1 随…...

Linux 计算机网络基础概念

目录 0.前言 1.计算机网络背景 1.1 独立模式 1.2 网络互联 1.3 局域网&#xff08;Local Area Network&#xff0c;LAN&#xff09; 1.4 广域网&#xff08;Wide Area Network&#xff0c;WAN&#xff09; 2.协议 2.1什么是协议 2.2协议分层和软件分层 2.3 OSI七层网络模型 2.3…...

qt QGraphicsEllipseItem详解

1、概述 QGraphicsEllipseItem是Qt框架中QGraphicsItem的一个子类&#xff0c;它提供了一个可以添加到QGraphicsScene中的椭圆项。QGraphicsEllipseItem表示一个带有填充和轮廓的椭圆&#xff0c;也可以用于表示椭圆段&#xff08;通过startAngle()和spanAngle()方法&#xff…...

Python websocket

router.websocket(/chat/{flow_id}) 接口代码&#xff0c;并了解其工作流程、涉及的组件以及如何基于此实现你的新 WebSocket 接口。以下内容将分为几个部分进行讲解&#xff1a; 接口整体概述代码逐行解析关键组件和依赖关系如何基于此实现新功能示例&#xff1a;创建一个新的…...

【MySQL-5】MySQL的内置函数

目录 1. 整体学习的思维导图 2. 日期函数 ​编辑 2.1 current_date() 2.2 current_time() 2.3 current_timestamp() 2.4 date(datetime) 2.5 now() 2.6 date_add() 2.7 date_sub() 2.8 datediff() 2.9 案例 2.9.1 创建一个出生日期登记簿 2.9.2 创建一个留言版 3…...

深度学习笔记之BERT(三)RoBERTa

深度学习笔记之RoBERTa 引言回顾&#xff1a;BERT的预训练策略RoBERTa训练过程分析静态掩码与动态掩码的比较模型输入模式与下一句预测使用大批量进行训练使用Byte-pair Encoding作为子词词元化算法更大的数据集和更多的训练步骤 RoBERTa配置 引言 本节将介绍一种基于 BERT \t…...

C++知识点总结(59):背包型动态规划

背包型动态规划 一、背包 dp1. 01 背包&#xff08;限量&#xff09;2. 完全背包&#xff08;不限量&#xff09;3. 口诀 二、例题1. 和是质数的子集数2. 黄金的太阳3. 负数子集和4. NASA的⻝物计划 一、背包 dp 1. 01 背包&#xff08;限量&#xff09; 假如有这几个物品&am…...

C++:反向迭代器的实现

反向迭代器的实现与 stack 、queue 相似&#xff0c;是通过适配器模式实现的。通过传入不同类型的迭代器来实现其反向迭代器。 正向迭代器中&#xff0c;begin() 指向第一个位置&#xff0c;end() 指向最后一个位置的下一个位置。 代码实现&#xff1a; template<class I…...

webGL入门教程_04vec3、vec4 和齐次坐标总结

vec3、vec4 和齐次坐标总结 1. vec3 和 vec4 1.1 什么是 vec3 和 vec4&#xff1f; vec3&#xff1a; GLSL 中的三维向量类型&#xff0c;包含 3 个浮点数&#xff1a;(x, y, z)。常用于表示三维坐标、RGB 颜色、法线、方向等。 vec4&#xff1a; GLSL 中的四维向量类型&…...

uniapp中父组件数组更新后与页面渲染数组不一致实战记录

简单描述一下业务场景方便理解: 商品设置功能,支持添加多组商品(点击添加按钮进行增加).可以对任意商品进行删除(点击减少按钮对选中的商品设置进行删除). 问题: 正常添加操作后,对已添加的任意商品删除后,控制台打印数组正常.但是与页面显示不一致.已上图为例,选中尾…...

优化 Conda 下载速度:详细的代理配置和网络管理策略

优化 Conda 下载速度&#xff1a;详细的代理配置和网络管理策略 为了彻底解决使用 Conda 下载 PyTorch 时遇到的速度问题&#xff0c;并确保下载过程稳定可靠&#xff0c;这需要一个详细、综合的技术方案。让我们更深入地分析问题原因&#xff0c;然后详尽地解释采取的解决策略…...

服务器遭受DDoS攻击后如何恢复运行?

当服务器遭受 DDoS&#xff08;分布式拒绝服务&#xff09;攻击 后&#xff0c;恢复运行需要快速采取应急措施来缓解攻击影响&#xff0c;并在恢复后加强防护以减少未来攻击的风险。以下是详细的分步指南&#xff1a; 一、应急处理步骤 1. 确认服务器是否正在遭受 DDoS 攻击 …...

MFC音视频播放器-支持电子放大等功能

前言 本播放器在VS2019下开发&#xff0c;使用ffmpegD3D实现视频播放渲染功能。同时本播放器支持录像功能、截图功能、音视频播放功能、码流信息显示、电子放大功能等。D3D的渲染同时支持surface和texture两种方式&#xff0c;电子放大功能是在D3D Texture方式下进行实现。以下…...

c语言编程1.17蓝桥杯历届试题-回文数字

题目描述 观察数字&#xff1a;12321&#xff0c;123321 都有一个共同的特征&#xff0c;无论从左到右读还是从右向左读&#xff0c;都是相同的。这样的数字叫做&#xff1a;回文数字。 本题要求你找到一些5位或6位的十进制数字。满足如下要求&#xff1a; 该数字的各个数位之…...

el-table 纵向 横向 多级表头

<el-table :data"tableData" class"diaTable":span-method"handleSpanMethod"border:header-cell-style"{background:#292929,color:#fff}"><!-- 纵向表头 --><el-table-column label"纵向表头" width"…...

uniapp开发微信小程序笔记8-uniapp使用vant框架

前言&#xff1a;其实用uni-app开发微信小程序的首选不应该是vant&#xff0c;因为vant没有专门给uni-app设置专栏&#xff0c;可以看到目前Vant 官方提供了 Vue 2 版本、Vue 3 版本和微信小程序版本&#xff0c;并由社区团队维护 React 版本和支付宝小程序版本。 但是vant的优…...

QMCDecode:3分钟解锁QQ音乐加密格式,让音乐真正属于你

QMCDecode&#xff1a;3分钟解锁QQ音乐加密格式&#xff0c;让音乐真正属于你 【免费下载链接】QMCDecode QQ音乐QMC格式转换为普通格式(qmcflac转flac&#xff0c;qmc0,qmc3转mp3, mflac,mflac0等转flac)&#xff0c;仅支持macOS&#xff0c;可自动识别到QQ音乐下载目录&#…...

重新定义下载体验:ctfileGet城通网盘高速下载完整指南

重新定义下载体验&#xff1a;ctfileGet城通网盘高速下载完整指南 【免费下载链接】ctfileGet 获取城通网盘一次性直连地址 项目地址: https://gitcode.com/gh_mirrors/ct/ctfileGet 你是否曾经面对城通网盘几十KB/s的下载速度感到绝望&#xff1f;当急需一个大文件时&a…...

如何用Mermaid Live Editor构建企业级实时图表系统:架构师的技术选型指南

如何用Mermaid Live Editor构建企业级实时图表系统&#xff1a;架构师的技术选型指南 【免费下载链接】mermaid-live-editor Edit, preview and share mermaid charts/diagrams. New implementation of the live editor. 项目地址: https://gitcode.com/GitHub_Trending/me/m…...

基于MCP协议与Playwright的AI智能体网页抓取工具部署与实战

1. 项目概述&#xff1a;一个为AI智能体打造的“网页抓取工具箱” 如果你正在开发或使用基于MCP&#xff08;Model Context Protocol&#xff09;的AI智能体&#xff0c;并且经常需要让它们从网页上获取结构化数据&#xff0c;那么你很可能已经遇到了一个核心痛点&#xff1a; …...

EDA工程师成长与验证技术演进:从算法到芯片的实践闭环

1. 从算法到芯片&#xff1a;一位EDA工程师的成长路径解析在半导体这个行当里待久了&#xff0c;你会发现&#xff0c;那些真正能把工具做“透”、把流程理“顺”的人&#xff0c;往往自己就亲手“焊”过板子、调过RTL、追过时序违例。Prakash Narain的故事&#xff0c;就是一个…...

Python: Condition Variable Pattern

项目结构&#xff1a; # encoding: utf-8 # 版权所有 2026 ©涂聚文有限公司™ # 许可信息查看&#xff1a;言語成了邀功盡責的功臣&#xff0c;還需要行爲每日來值班嗎 # 描述&#xff1a;Condition Variable Pattern 条件变量模式 # Author : geovindu,Geovin Du …...

AI智能体评测指南:AgentBoard开源平台实战与多维能力评估

1. 项目概述&#xff1a;AgentBoard是什么&#xff0c;以及它为何重要最近在AI智能体评测这个圈子里&#xff0c;一个叫AgentBoard的开源项目讨论度挺高。这个项目由jbcrane13团队发起&#xff0c;本质上是一个用于系统性评估和对比AI智能体&#xff08;AI Agent&#xff09;性…...

AI大模型选型指南:构建开源比较平台的技术实践与架构解析

1. 项目概述&#xff1a;为什么我们需要一个AI模型“选型指南”&#xff1f;最近在GitHub上闲逛&#xff0c;发现了一个挺有意思的项目&#xff0c;叫ai-llm-comparison。光看名字&#xff0c;你大概就能猜到它是干嘛的——一个关于人工智能大语言模型的比较项目。说实话&#…...

PhySO快速入门指南:5分钟学会使用符号回归发现物理规律

PhySO快速入门指南&#xff1a;5分钟学会使用符号回归发现物理规律 【免费下载链接】PhySO Physical Symbolic Optimization 项目地址: https://gitcode.com/gh_mirrors/ph/PhySO PhySO&#xff08;Physical Symbolic Optimization&#xff09;是一款强大的符号回归工具…...

别再手动翻译了!用Python的googletrans库5分钟搞定批量文件翻译(附实战代码)

用Python自动化批量翻译&#xff1a;googletrans实战进阶指南 当你面对上百页的外文文档需要翻译时&#xff0c;是否还在复制粘贴到网页翻译工具&#xff1f;作为开发者&#xff0c;我们完全可以用Python的googletrans库构建自动化翻译流水线。本文将带你超越基础的单句翻译&am…...