【数据结构与算法】二叉搜索树插入/查询的应用

news/2025/2/6 9:49:31 标签: c++, 算法, 开发语言, c, 数据结构
cle class="baidu_pl">
cle_content" class="article_content clearfix">
content_views" class="markdown_views prism-atom-one-light"> cap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">

导语

在上周的文章中࿰c;我们了解了二叉搜索树这一强大的数据结构

数据结构class="tags" href="/tags/SuanFa.html" title=算法>算法-二叉搜索树的定义和插入实现

上次࿰c;我们已经实现了插入节点的功能

要想具体应用到class="tags" href="/tags/SuanFa.html" title=算法>算法的整体设计中࿰c;我们还需要根据运用场景进行改动

让我们先从一个经典的问题开始

例题-第k小的数

[题目传送门]here

题目大意:

有一个初始为空的数列

现在总共有class="katex--inline">class="katex">class="katex-mathml"> T T class="katex-html">class="base">class="strut" style="height: 0.6833em;">class="mord mathnormal" style="margin-right: 0.1389em;">T个操作࿰c;每个都是以下两种之一:

class="katex--inline">class="katex">class="katex-mathml"> 1    k 1\ \ k class="katex-html">class="base">class="strut" style="height: 0.6944em;">class="mord">1class="mspace"> class="mspace"> class="mord mathnormal" style="margin-right: 0.0315em;">k :向数列中添加一个数class="katex--inline">class="katex">class="katex-mathml"> k k class="katex-html">class="base">class="strut" style="height: 0.6944em;">class="mord mathnormal" style="margin-right: 0.0315em;">k
class="katex--inline">class="katex">class="katex-mathml"> 2    k 2\ \ k class="katex-html">class="base">class="strut" style="height: 0.6944em;">class="mord">2class="mspace"> class="mspace"> class="mord mathnormal" style="margin-right: 0.0315em;">k :查询第class="katex--inline">class="katex">class="katex-mathml"> k k class="katex-html">class="base">class="strut" style="height: 0.6944em;">class="mord mathnormal" style="margin-right: 0.0315em;">k小的数

(时间限制1000ms)

直觉

首先我们想到的暴力做法就是每次数据进来之后就排序

但是很明显࿰c;数据规模在class="katex--inline">class="katex">class="katex-mathml"> 1 0 5 10^5 class="katex-html">class="base">class="strut" style="height: 0.8141em;">class="mord">1class="mord">class="mord">0class="msupsub">class="vlist-t">class="vlist-r">class="vlist" style="height: 0.8141em;">class="" style="top: -3.063em; margin-right: 0.05em;">class="pstrut" style="height: 2.7em;">class="sizing reset-size6 size3 mtight">class="mord mtight">5量级࿰c;

题目要求的时间复杂度显然是在class="katex--inline">class="katex">class="katex-mathml"> O ( n l o g n ) O(nlogn) class="katex-html">class="base">class="strut" style="height: 1em; vertical-align: -0.25em;">class="mord mathnormal" style="margin-right: 0.0278em;">Oclass="mopen">(class="mord mathnormal">nclass="mord mathnormal" style="margin-right: 0.0197em;">lclass="mord mathnormal">oclass="mord mathnormal" style="margin-right: 0.0359em;">gclass="mord mathnormal">nclass="mclose">)左右

如果直接使用sort肯定会超时

假设询问次数为class="katex--inline">class="katex">class="katex-mathml"> n n class="katex-html">class="base">class="strut" style="height: 0.4306em;">class="mord mathnormal">nc;什么数据结构能以class="katex--inline">class="katex">class="katex-mathml"> l o g n logn class="katex-html">class="base">class="strut" style="height: 0.8889em; vertical-align: -0.1944em;">class="mord mathnormal" style="margin-right: 0.0197em;">lclass="mord mathnormal">oclass="mord mathnormal" style="margin-right: 0.0359em;">gclass="mord mathnormal">n的复杂度完成查询呢

我们想到了二叉搜索树

正解思路

假如现在有这么一棵二叉搜索树(数字为对应节点的权值):
c="https://i-blog.csdnimg.cn/direct/9cdad0495c04442883a3aace04cd6a47.png" alt="在这里插入图片描述" />
我们要查找第3小的数࿰c;怎么办?

这时候就需要引入一个新的参数来表示每个节点子树的大小了

至于为何࿰c;往下看便是

我们的插入部分代码成了这样:

<code class="prism language-cpp">class="token keyword">struct class="token class-name">Nodeclass="token punctuation">{
    class="token keyword">int keyclass="token punctuation">, lclass="token punctuation">, rclass="token punctuation">, szclass="token punctuation">, cntclass="token punctuation">;
class="token punctuation">}trclass="token punctuation">[MaxNclass="token punctuation">]class="token punctuation">;

class="token keyword">void class="token function">insclass="token punctuation">(class="token keyword">int class="token operator">&posclass="token punctuation">, class="token keyword">int xclass="token punctuation">)class="token punctuation">{
    class="token keyword">ifclass="token punctuation">(pos class="token operator">== class="token number">0class="token punctuation">)class="token punctuation">{
        pos class="token operator">= class="token operator">++nclass="token punctuation">;
        trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.key class="token operator">= xclass="token punctuation">;
        trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.sz class="token operator">= trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.cnt class="token operator">= class="token number">1class="token punctuation">;
        class="token keyword">return class="token punctuation">;
    class="token punctuation">}
    trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.szclass="token operator">++class="token punctuation">;
    class="token keyword">ifclass="token punctuation">(trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.key class="token operator">== xclass="token punctuation">)class="token punctuation">{
        trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.cntclass="token operator">++class="token punctuation">;
        class="token keyword">return class="token punctuation">;
    class="token punctuation">}
    class="token keyword">ifclass="token punctuation">(x class="token operator">< trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.keyclass="token punctuation">) class="token function">insclass="token punctuation">(trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.lclass="token punctuation">, xclass="token punctuation">)class="token punctuation">;
    class="token keyword">else class="token function">insclass="token punctuation">(trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.rclass="token punctuation">, xclass="token punctuation">)class="token punctuation">;
class="token punctuation">}
code>

首先我们以人类的思维思考一种简单的情况:

cnt1_71">cnt全为1

我们模拟一下过程如下图:

c="https://i-blog.csdnimg.cn/direct/0125efd455724a3586f7e1b76b5c5867.png" alt="在这里插入图片描述" />
首先我们从根节点开始看起

我们要查找的是第三小的数࿰c;发现左子树多于3个节点

又因为左子树上的数一定小于根节点

所以目标必然是左子树上第三小的数࿰c;往左找!

接下来࿰c;发现新的节点左边只有一个节点

即便是加上它自己也不可能有第三小

所以就往右找!

但是一定要注意࿰c;在右子树找的时候找的并不是第三小的数

而是要除去左子树和根节点的所有数c;因为它们都比第三小的数更小!

依次一直递归࿰c;直到在大小为1的子树中找第1小的数࿰c;我们就找到了答案!

普遍情况

同理࿰c;cnt不全为1是时也可以用上面的思路

一般地࿰c;对于节点class="katex--inline">class="katex">class="katex-mathml"> n n class="katex-html">class="base">class="strut" style="height: 0.4306em;">class="mord mathnormal">nc;需要分几种情况讨论:

class="katex--inline">class="katex">class="katex-mathml"> t r [ n . l ] . s z ≤ k tr[n.l].sz \leq k class="katex-html">class="base">class="strut" style="height: 1em; vertical-align: -0.25em;">class="mord mathnormal">tclass="mord mathnormal" style="margin-right: 0.0278em;">rclass="mopen">[class="mord mathnormal">nclass="mord">.class="mord mathnormal" style="margin-right: 0.0197em;">lclass="mclose">]class="mord">.class="mord mathnormal" style="margin-right: 0.044em;">szclass="mspace" style="margin-right: 0.2778em;">class="mrel">≤class="mspace" style="margin-right: 0.2778em;">class="base">class="strut" style="height: 0.6944em;">class="mord mathnormal" style="margin-right: 0.0315em;">k目标在左子树࿰c;往左找

否则若class="katex--inline">class="katex">class="katex-mathml"> t r [ n . l ] . s z + n . c n t tr[n.l].sz + n.cnt class="katex-html">class="base">class="strut" style="height: 1em; vertical-align: -0.25em;">class="mord mathnormal">tclass="mord mathnormal" style="margin-right: 0.0278em;">rclass="mopen">[class="mord mathnormal">nclass="mord">.class="mord mathnormal" style="margin-right: 0.0197em;">lclass="mclose">]class="mord">.class="mord mathnormal" style="margin-right: 0.044em;">szclass="mspace" style="margin-right: 0.2222em;">class="mbin">+class="mspace" style="margin-right: 0.2222em;">class="base">class="strut" style="height: 0.6151em;">class="mord mathnormal">nclass="mord">.class="mord mathnormal">cclass="mord mathnormal">nclass="mord mathnormal">t要找的数就是根节点

否则目标在右子树࿰c;往右找


到这里࿰c;正解就呼之欲出了——

正解代码

<code class="prism language-cpp">class="token macro property">class="token directive-hash">#class="token directive keyword">includeclass="token string"><iostream>
class="token keyword">using class="token keyword">namespace stdclass="token punctuation">;
class="token macro property">class="token directive-hash">#class="token directive keyword">define class="token macro-name">MaxN class="token expression">class="token number">100005
class="token macro property">class="token directive-hash">#class="token directive keyword">define class="token macro-name function">Forclass="token expression">class="token punctuation">(iclass="token punctuation">, jclass="token punctuation">, kclass="token punctuation">) class="token keyword">forclass="token punctuation">(class="token keyword">int i class="token operator">= jclass="token punctuation">; i class="token operator"><= kclass="token punctuation">; iclass="token operator">++class="token punctuation">)

class="token keyword">int nclass="token punctuation">, qclass="token punctuation">, rtclass="token punctuation">;

class="token keyword">struct class="token class-name">Nodeclass="token punctuation">{
    class="token keyword">int keyclass="token punctuation">, lclass="token punctuation">, rclass="token punctuation">, szclass="token punctuation">, cntclass="token punctuation">;
class="token punctuation">}trclass="token punctuation">[MaxNclass="token punctuation">]class="token punctuation">;

class="token keyword">void class="token function">insclass="token punctuation">(class="token keyword">int class="token operator">&posclass="token punctuation">, class="token keyword">int xclass="token punctuation">)class="token punctuation">{		class="token comment">//插入节点x
    class="token keyword">ifclass="token punctuation">(pos class="token operator">== class="token number">0class="token punctuation">)class="token punctuation">{
        pos class="token operator">= class="token operator">++nclass="token punctuation">;
        trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.key class="token operator">= xclass="token punctuation">;
        trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.sz class="token operator">= trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.cnt class="token operator">= class="token number">1class="token punctuation">;
        class="token keyword">return class="token punctuation">;
    class="token punctuation">}
    trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.szclass="token operator">++class="token punctuation">;
    class="token keyword">ifclass="token punctuation">(trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.key class="token operator">== xclass="token punctuation">)class="token punctuation">{
        trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.cntclass="token operator">++class="token punctuation">;
        class="token keyword">return class="token punctuation">;
    class="token punctuation">}
    class="token keyword">ifclass="token punctuation">(x class="token operator">< trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.keyclass="token punctuation">) class="token function">insclass="token punctuation">(trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.lclass="token punctuation">, xclass="token punctuation">)class="token punctuation">;
    class="token keyword">else class="token function">insclass="token punctuation">(trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.rclass="token punctuation">, xclass="token punctuation">)class="token punctuation">;
class="token punctuation">}

class="token keyword">int class="token function">queryclass="token punctuation">(class="token keyword">int posclass="token punctuation">, class="token keyword">int kclass="token punctuation">)class="token punctuation">{		class="token comment">//在根节点编号pos处找第k小的数
    class="token keyword">ifclass="token punctuation">(trclass="token punctuation">[trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.lclass="token punctuation">]class="token punctuation">.sz class="token operator">>= kclass="token punctuation">)class="token punctuation">{	class="token comment">//分类
        class="token keyword">return class="token function">queryclass="token punctuation">(trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.lclass="token punctuation">, kclass="token punctuation">)class="token punctuation">;	class="token comment">//左子树
    class="token punctuation">}class="token keyword">else class="token keyword">ifclass="token punctuation">(trclass="token punctuation">[trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.lclass="token punctuation">]class="token punctuation">.sz class="token operator">+ trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.cnt class="token operator">>= kclass="token punctuation">)class="token punctuation">{
        class="token keyword">return trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.keyclass="token punctuation">;			class="token comment">//根节点
    class="token punctuation">}class="token keyword">elseclass="token punctuation">{							class="token comment">//右子树
        class="token keyword">return class="token function">queryclass="token punctuation">(trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.rclass="token punctuation">, kclass="token operator">-trclass="token punctuation">[trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.lclass="token punctuation">]class="token punctuation">.szclass="token operator">-trclass="token punctuation">[posclass="token punctuation">]class="token punctuation">.cntclass="token punctuation">)class="token punctuation">;
    class="token punctuation">}
class="token punctuation">}

class="token keyword">int class="token function">mainclass="token punctuation">(class="token punctuation">)
class="token punctuation">{
    cin class="token operator">>> qclass="token punctuation">;
    class="token keyword">whileclass="token punctuation">(qclass="token operator">--class="token punctuation">)class="token punctuation">{
        class="token keyword">int opclass="token punctuation">, xclass="token punctuation">;
        cin class="token operator">>> op class="token operator">>> xclass="token punctuation">; 
        class="token keyword">ifclass="token punctuation">(op class="token operator">== class="token number">1class="token punctuation">)class="token punctuation">{
            class="token function">insclass="token punctuation">(rtclass="token punctuation">, xclass="token punctuation">)class="token punctuation">;
        class="token punctuation">}class="token keyword">elseclass="token punctuation">{
            class="token keyword">ifclass="token punctuation">(x class="token operator">> trclass="token punctuation">[class="token number">1class="token punctuation">]class="token punctuation">.szclass="token punctuation">) cout class="token operator"><< class="token operator">-class="token number">1 class="token operator"><< endlclass="token punctuation">;
            class="token keyword">else cout class="token operator"><< class="token function">queryclass="token punctuation">(class="token number">1class="token punctuation">, xclass="token punctuation">) class="token operator"><< endlclass="token punctuation">;
        class="token punctuation">}
    class="token punctuation">}
    class="token keyword">return class="token number">0class="token punctuation">;
class="token punctuation">}
code>

总结

在这篇文章中࿰c;我们通过经典的第k小问题了解了二叉搜索树的运用

实际上࿰c;它还有更加丰富的拓展和运用࿰c;比如treap, AVLtree

更多内容敬请期待下期数据结构class="tags" href="/tags/SuanFa.html" title=算法>算法!

最后࿰c;制作实在不易。如果你喜欢这篇文章࿰c;可以点个免费的关注和免费的赞

非常感谢大家的支持࿰c;你的支持是作者最大的动力!

我们下期再见!


http://www.niftyadmin.cn/n/5842844.html

相关文章

微深节能 智能工厂天车无人驾驶项目 格雷母线

在工业4.0的浪潮下&#xff0c;智能工厂的建设已成为制造业转型升级的重要方向。作为智能工厂的核心组成部分&#xff0c;天车无人驾驶系统的精准定位与自动化控制显得尤为关键。武汉市微深节能科技有限公司凭借其领先的格雷母线高精度位移测量系统&#xff0c;为智能工厂的天车…

YOLOv11-ultralytics-8.3.67部分代码阅读笔记-autobackend.py

autobackend.py ultralytics\nn\autobackend.py 目录 autobackend.py 1.所需的库和模块 2.def check_class_names(names): 3.def default_class_names(dataNone): 4.class AutoBackend(nn.Module): 1.所需的库和模块 # Ultralytics &#x1f680; AGPL-3.0 License …

【怎么用系列】短视频戒除-1-对推荐算法进行干扰

如今推荐算法已经渗透到人们生活的方方面面&#xff0c;尤其是抖音等短视频核心就是推荐算法。 【短视频的危害】 1> 会让人变笨&#xff0c;慢慢让人丧失注意力与专注力 2> 让人丧失阅读长文的能力 3> 让人沉浸在一个又一个快感与嗨点当中。当我们刷短视频时&#x…

基于全志H616的智能家居

1.接线 2.配置语音模块 3.接上串口烧入安装包并且用电脑串口测试 4.板子测试语音模块 5.接入阿里云人脸识别 人脸识别示例代码的位置 导入并配置示例代码 修改“default” face.py # -*- coding: utf-8 -*- # 引入依赖包 # pip install alibabacloud_facebody20191230import …

Debian 安装 Nextcloud 使用 MariaDB 数据库 + Caddy + PHP-FPM

前言 之前通过 docker在ubuntu上安装Nextcloud&#xff0c;但是现在我使用PVE安装Debian虚拟机&#xff0c;不想通过docker安装了。下面开始折腾。 安装过程 步骤 1&#xff1a;更新系统并安装必要的软件 sudo apt update && sudo apt upgrade -y sudo apt install…

大一计算机的自学总结:数据结构设计相关题

前言 说实在的&#xff0c;感觉这种设计数据结构的题比链表题还要ex&#xff0c;尤其是当哈希表和链表一起上的时候&#xff01; 一、设计有setAll功能的哈希表 #include <bits/stdc.h> using namespace std;int cnt0,setAllTime0,setAllValue; map<int,pair<in…

AI工具如何辅助写文章(科研版)

文章总览:[YuanDaiMa2048博客文章总览](https://blog.csdn.net/2301_79288416/article/details/137397359?spm=1001.2014.3001.5501)https://blog.csdn.net/2301_79288416/article/details/137397359?spm=1001.2014.3001.5501 在科研领域,撰写论文是一个复杂且耗时的过程。…

63.网页请求与按钮禁用 C#例子 WPF例子

这是一个简单的从网页获得一些数据的代码&#xff0c;使用了按钮禁用功能防止连续点击。使用了Dispatcher.Invoke从UI线程更新。使用了throw丢出异常。 System.Windows.Application.Current.Dispatcher.Invoke(() >{TextBlock2.Text $"错误&#xff1a;{ex.Message}&q…