C++之二叉搜索

news2024/12/25 8:51:54

1.二叉搜索树的概念

二叉搜索树又称为二叉排序树,它有以下的特点。

1.如果它的左子树不为空,则左子树上所以结点的值都小于等于根结点的值

2.如果它的右子树不为空,则右子树上所有结点都大于等于根结点的值

3.它的左右子树也分别为二叉搜索树

4.二叉搜索树中可以支持插入相等的值,也可以不支持插入相等的值,具体看使用场景定义

2.二叉搜索树的性能分析 

最优情况下,二叉树搜索树为完全二叉树,其高度为O(log2 N

最差情况下,二叉搜索树退化为单支树,其高度为O(N/2)

所以综合来看二叉搜索树增删查改的时间复杂度为:O(N)

3.二叉搜索树的插入

插入的具体过程如下:

1.树为空,则直接新增结点,赋值给root指针

2.树不为空,按二叉搜索树的性质,小的往左边插,大的往右边插。

3,如果支持插入相等的值,插入值跟当前结点相等的值可以往右走,也可以往左走,找到空位置,插入新结点。

4.二叉搜索树的查找

1.从根开始比较,查找X,X比根的值大则往右边走查找,X比根值小则往左边走查找。

2.最多查找高度次,走到空,还没找到,这个值不存在。

3.如果不支持插入相等的值,找到X即可返回

4.如果支持插入相等的值,就要返回最下方的X的值,如下图,要返回最下面的3:

5.二叉搜索树的删除 

首先查找元素是否在二叉搜索树中,如果不存在,则返回false。

如果查找元素则可以分为以下四种情况:

1.要删除结点N左右孩子均为空

2.要删除的结点N左孩子位空,右孩子结点不为空

3.要删除的结点N右孩子位空,左孩子结点不为空

4.要删除的结点N左右孩子结点都不为空

对应以上四种情况的解决方案:

解决1:把N结点父亲对应孩子指针指向空,直接删除N结点

解决2:把N结点父亲对应孩子指针指向右孩子结点,直接删除N结点

解决3:   把N结点父亲对应孩子指针指向左孩子结点,直接删除N结点

解决4:这样的情况无法直接删除N结点,因为N的两个孩子无处安放,只能用替换法删除,找N左子树的值最大结点R(最右结点)或者N右子树的值最小结点R(最左结点)替代N,因为这两个结点中任意一个,放到N的位置,都满足二叉搜索树的规则。替代N的意思就是N和R两个结点的值交换。最后可以根据解决1的方法删除N。

6.二叉搜索树的实现代码

template<class K>

struct BSTNode

{

      K_key;

      BSTNode<K>*_left;

      BSTNode<K>*_right;

      BSTNode(const K& key)

                     :_key(key)

                     ,_left(nullptr)

                     ,_right(nullptr)

 {}

};

 //以下为二叉搜索树的视线

template<class K>

class BSTree

{

     typedef BSTNode<K> Node;

public:

     bool insert(const K& key)

     {

            if(_root == nullptr)

            {

                 _root = new Node(key);

                 return true;

            }

            Node* parent = nullptr;

            Node*cur = _root;

            while(cur)

          {

             if(cur->_key>key)

           {
                 parent = cur;

                 cur = cur->left;

          }

           else if(cur->_key<key)

           {

               parent = cur;

               cur = cur->right;

           }

           else 

          {
               return false;

          }
        }

           cur = new Node(key)

       if(parent->_key<key)

        {

              parent->right = cur;

        }

       if(parent->_key>key)

        {

              parent->left = cur;

        }

    return true;

 }

//以下为二叉搜索树的查找功能

   bool  Find(const K&key)

 {

     Node*cur = _root;

     while(cur)

 {
      if(cur->_key <key)

    {

        cur = cur->right;

    }

      else if(cur->_key>key)

    {

        cur = cur->left;

    }     

       else

    {

        return true;

     }

    return false;

 }

//以下为二叉搜索树的删除功能

  bool  Erase(const K& key)

 {
       Node* parent = nullptr;

       Node*cur =  _root;

       while(cur)

    {
       if(cur->_key < key)

       {
           parent = cur;

           cur = cur->right;

       } 

       else if

      {

           parent = cur;

           cur = cur->left;

      }

      else

     {

          if(cur->left = nullptr)

          {

              if(parent == nullptr)

            { 

                 _root = cur->right;

            }

            else

            {

                  if(parent->left == cur)

                  { 

                         parent->left = cur->right;

                  }

                  else

                  {

                        parent->right = cur->right;

                  }

            }

           delete cur;

           return true;

           else if(cur->right = nullptr)

          {

              if(parent == nullptr)

             { 

                 _root = cur->left;

             }

            else

            {

                  if(parent->left == cur)

                  { 

                         parent->left = cur->left;

                  }

                  else

                  {

                        parent->right = cur->left;

                  }

             }

              delete cur;

              return true;

         }

         

        {

            Node*minp  = cur;

            Node*min    = cur->right;

            while(min->left)

          {

             minp = min;

             min  = min->left;

          }

          cur->key = min->key;

          if(minp->left == min)

            minp->left = min->right;

          else

            minp->right = min->right;

          delete min;

           return true;

         }

      }

   }   

     return false;

           

        }

        

           

7.二叉搜索树key和key/value使用场景

    7.1 key搜索场景

只有key作为关键码,结构中只需要存储key即可,关键码即为需要搜索到的值,搜索场景只需要判断key在不在。key的搜索场景实现的二叉树搜索树支持增删查,不支持修改的原因是修改key会破坏二叉树的结构。

key可以用来检查一篇英文文章单词拼写是否正确:将词库中所有单词放入二叉搜索树,读取文章中的单词,查找是否在二叉搜索树中,不在则波浪线标红提示。

    7.2 key/value搜索场景

每一个关键码key,都有与之对应的值value,value可以为任意类型对象。树的结构中除了需要存储key还要存储对应的value。key/value的搜索场景支持修改,但还是不支持修改key。

 key/value可以统计一篇文章中单词出现的次数:读取一个单词,查找单词是否存在不存在这个说明第一次出现,(单词,1),单词存在,则++单词对应的次数。

     7.3 key/value二叉搜索树代码的实现

template<class K,class V>

struct BSNode

{
     K_key;

     V_value;

    BSNode<K,V>*_left;

    BSNode<K,V>*_right;

    BSNode(const K&key,const V& value)

                   : _key(key)

                   ,_value(value)

                   ,_left(nullptr)

                   ,_right(nullptr)

       {}

};

template<class K,class V>

class BSTree

{

      typedef BSNode<K,N> Node;

public:

      BSTree() = default;

      

     BSTree(const BSTree<K, V>& t)
   {
       _root = Copy(t._root);
   }
    BSTree<K, V>& operator=(BSTree<K, V> t)
   {
     swap(_root, t._root);
     return *this;
   }
   ~BSTree()
   {
      Destroy(_root);
      _root = nullptr;
   }
   
   
   bool Insert(const K& key, const V& value)
{
    if (_root == nullptr)
{
    _root = new Node(key, value);
    return true;
}
   Node* parent = nullptr;
   Node* cur = _root;
while (cur)
{
  if (cur->_key < key)
  {
    parent = cur;
    cur = cur->_right;
  }
  else if (cur->_key > key)
 {
    parent = cur;
   cur = cur->_left;
 }
else
    {
      return false;
    }
}
    cur = new Node(key, value);
   if (parent->_key < key)
{
   parent->_right = cur;
}
  else
{
    parent->_left = cur;
}
    return true;
}
Node* Find(const K& key)
{
    Node* cur = _root;
    while (cur)
{
   if (cur->_key < key)
  {
   cur = cur->_right;
  }
 else if (cur->_key > key)
  {
   cur = cur->_left;
  }
else
  {
  return cur;
  }
}
  return nullptr;
}
 
bool Erase(const K& key)
{
     Node* parent = nullptr;
     Node* cur = _root;
     while (cur)
{
     if (cur->_key < key)
    {
      parent = cur;
      cur = cur->_right;
    }
    else if (cur->_key > key)
    {
       parent = cur;
       cur = cur->_left;
    }  
 
  else
{
  if (cur->_left == nullptr)
    {
      if (parent == nullptr)
     {
       _root = cur->_right;
     }
     else
    {
      if (parent->_left == cur)
      parent->_left = cur->_right;
      else
      parent->_right = cur->_right;
    }
      delete cur;
      return true;
    }
   else if (cur->_right == nullptr)
  {
     if (parent == nullptr)
   {
     _root = cur->_left;
   }
    else
  {
    if (parent->_left == cur)
    parent->_left = cur->_left;
   else
   parent->_right = cur->_left;
  }
   delete cur;
   return true;
}
else
 {
    
   Node* rightMinP = cur;
   Node* rightMin = cur->_right;
    while (rightMin->_left)
{
   rightMinP = rightMin;
   rightMin = rightMin->_left;
}
cur->_key = rightMin->_key;
if (rightMinP->_left == rightMin)
rightMinP->_left = rightMin->_right;
else
rightMinP->_right = rightMin->_right;
 
delete rightMin;
return true;
  }
 }
}
return false;
}
void InOrder()
{
    _InOrder(_root);
    cout << endl;
}
 private:
void _InOrder(Node* root)
{
   if (root == nullptr)
  {
    return;
  }
   _InOrder(root->_left);
  cout << root->_key << ":" << root->_value << endl;
   _InOrder(root->_right);
}
void Destroy(Node* root)
{
if (root == nullptr)
       return;
Destroy(root->_left);
Destroy(root->_right);
delete root;
}
 
Node* Copy(Node* root)
{
   if (root == nullptr)
      return nullptr;
  Node* newRoot = new Node(root->_key, root->_value);
  newRoot->_left = Copy(root->_left);
  newRoot->_right = Copy(root->_right);
   return newRoot;
}
private:
   Node* _root = nullptr;
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2171604.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Lab1:虚拟机kolla安装部署openstack,并创建实例

实验内容&#xff1a; 创建并配置虚拟机安装OpenStack创建镜像创建实例类型选择网络配置创建实例 1、选择一个适合你的系统的虚拟机管理软件&#xff1a; VirtualBox &#xff08;推荐&#xff09; VMWare 其他 2、下载 .iso 镜像文件 openstack S 版本 iso 链接&#xff1…

Llama系列迈向多模态新时代:3.2版本开源超越闭源,并携手Arm推出手机优化版

在多模态领域&#xff0c;开源模型也超闭源了&#xff01; 就在刚刚结束的 Meta 开发者大会上&#xff0c;Llama 3.2 闪亮登场&#xff1a; 这回不仅具备了多模态能力&#xff0c;还和 Arm 等联手&#xff0c;推出了专门为高通和联发科硬件优化的 “移动” 版本。 具体来说&a…

jmeter压测常见报错总结

address already in use:connect 报错原因&#xff1a; 1、windows系统为了保护本机,限制了其他机器到本机的连接数. 2、TCP/IP 可释放已关闭连接并重用其资源前&#xff0c;必须经过的时间。关闭和释放之间的此时间间隔通称 TIME_WAIT 状态或两倍最大段生命周期&#xff08…

javaJUC基础

JUC基础知识 多线程 管程 Monitor&#xff0c;也就是平时所说的锁。Monitor其实是一种同步机制&#xff0c;它的义务是保证&#xff08;同一时间&#xff09;只有一个线程可以访问被保护的数据和代码块&#xff0c;JVM中同步是基于进入和退出监视器&#xff08;Monitor管程对…

【MySQL】数据库表的基本查询——增删查改

W...Y的主页 &#x1f60a; 代码仓库分享&#x1f495; 目录 表的增删改查 Create 单行数据 全列插入 多行数据 指定列插入 插入否则更新 替换 Retrieve SELECT 列 全列查询 指定列查询 查询字段为表达式 为查询结果指定别名 结果去重 WHERE 条件 结果排序 筛选…

ETLCloud携手ClickHouse:高效的数据查询效率

自从大数据处理技术走进大众视野、开源项目Hadoop的出现&#xff0c;以前受制于数据库处理能力的大数据技术蓬勃发展&#xff0c;传统关系型数据库所构建的数据仓库&#xff0c;被以Hive为代表的大数据技术所取代&#xff0c;随着技术不断发展&#xff0c;Hadoop虽然带来了诸多…

Harbor的安装与使用

任务分析 一、规划节点 IP地址 主机名 节点 192.168.20.20 master 容器master节点 192.168.20.21 node 容器worker节点 二、基础准备 镜像使用CentOS7.9&#xff08;主机配置自定义&#xff0c;推荐配置4vCPU/12G内存/100G硬盘&#xff09;&#xff0c;使用这两台云…

韦东山FreeRTOS笔记

介绍 这篇文章是我学习FreeRTOS的笔记 学的是哔哩哔哩韦东山老师的课程 在学习FreeRTOS之前已经学习过江协的标准库和一丢丢的超子说物联网的HAL了。他们讲的都很不错 正在更新&#xff0c; 大家可以在我的Gitee仓库中下载笔记源文件、项目资料等 笔记源文件可以在Notion…

鸿蒙OS开发之动画相关示例分享, 关于弹出倒计时动画的实战案例源码分享

基础动画案例 Entry Component struct Index {StatebtnWidth:number 200 // 按钮的宽度StatebtnHeight:number 100 // 按钮的高度build() {Row(){Column(){Button("测试").width(this.btnWidth).height(this.btnHeight)// 按钮: 用来启动动画Button("动画开始…

USB2.0主机设备检测过程以及信号分析

一&#xff0c;USB协议发展 USB接口自1994年推出以来&#xff0c;经过30年的发展&#xff0c;从USB1.0发展到了现在的USB4.0&#xff0c;传输速率也从最开始的1.5Mbps&#xff0c;大幅提高到了最新的40Gbps。 USB协议按照速度等级和连接方式分可分为7个版本&#xff0c;但是从…

docker -私有镜像仓库 - harbor安装

文章目录 1、镜像仓库简介2、Harbor简介3、下载与安装3.1、下载3.2、安装3.2.1、上传harbor-offline-installer-v2.8.2.tgz到虚拟机中解压并修改配置文件3.2.2、解压tgz包3.2.3、切换到解压缩后的目录下3.2.4、准备配置文件3.2.5、修改配置文件 4、启动Harbor5、启动关闭命令6、…

为什么这款智能在线派单软件成为行业首选?

智能在线派单软件通过自动化任务分配等提升效率&#xff0c;ZohoDesk因其全方位服务管理、智能分配、定制性强、数据分析等功能&#xff0c;成为企业优选。实例涵盖物流、家政、维修、医疗等行业&#xff0c;提高效率和客户满意度。 一、智能在线派单软件有什么功能 在深入探讨…

【Java】包装类【主线学习笔记】

文章目录 前言包装类基本数据类型与包装类之间的转换基本数据类型转换为包装类可以通过以下几种方式&#xff1a;包装类转换为基本数据类型可以通过以下几种方式&#xff1a;初始化值不同与String之间的转换 前言 Java是一门功能强大且广泛应用的编程语言&#xff0c;具有跨平台…

带你重新深入了解STM32单片机

目录 一. 前言 二. 片上资源外设 三. 单片机命名规则 四. STM32的系统结构 五. STM32F103C8T6的引脚定义 六. 启动配置 一. 前言 本篇文章主要讲述对STM32单片机的介绍&#xff0c;包括片上资源和外设&#xff0c;STM32产品系列&#xff0c;内存存储器容量以及STM32的系统…

Java每日面试题(JVM)(day15)

目录 Java对象内存布局markWord 数据结构JDK1.8 JVM 内存结构JDK1.8堆内存结构GC垃圾回收如何发现垃圾如何回收垃圾 JVM调优参数 Java对象内存布局 markWord 数据结构 JDK1.8 JVM 内存结构 程序计数器: 线程私有&#xff0c;记录代码执行的位置. Java虚拟机栈: 线程私有&#…

服务器操作系统【sar 命令】

sar 安装、语法参数说明以及示例 文章目录 功能概述一、功能介绍1.安装配置2. 配置3. 启动二、sar 语法及参数说明三、示例及释义1.汇报 io 传输速率信息2.内存分页信息3.块设备状态信息4.hugepages 利用率统计信息5.列长度和负载平均值6.内存利用率统计信息7.swap 交换空间利用…

中国的互联网电商,终于还是“连上了”

什么才是更好的互联网&#xff1f; 答案很简单&#xff1a;真正的互联。 9月26日&#xff0c;据市场消息&#xff0c;京东物流和菜鸟速递将分别接入淘天、京东平台。同时&#xff0c;京东也将在“双11”前开通支付宝支付&#xff0c;时隔13年再度携手阿里支付体系。 消息一出…

【Redis入门到精通八】Redis事务与MySQL事务对比

目录 事务 1.MySQL中事务的特性 2.Redis事务与MySQL事务的区别 3.Redis事务操作演示 事务 什么是事务呢&#xff1f;事务的概念其实就是把一系列操作绑定成一组&#xff0c;让这一组操作能够批量执行&#xff0c;不过在MySQL中有复杂的机制能够保证这一组操作执行并且一定能…

降AI率不再难:芝士AI去痕工具,让论文原创性飙升~~~

降AI率不再难&#xff1a;芝士AI去痕工具&#xff0c;让你的论文原创性飙升 如何有效降低AIGC论文的重复率&#xff0c;也就是我们说的aigc如何降重&#xff1f;AIGC疑似度过高确实是个比较愁人的问题。 如果你用AI帮忙写了论文&#xff0c;就一定要在交稿之前做一下AIGC降重…

征程6 上基于 DEB 工具实现包管理

1.引言 在开发、调测过程中&#xff0c;开发人员需要将系统软件、应用软件部署到 Soc 板端&#xff0c;以用于运行调试。传统的部署方式是通过解压复制或者调用部署脚本。这样的部署方式需要有着方式不统一、维护投入大的缺点。 在 linux 系统上&#xff0c;大多采用包管理的…