C++之二叉搜索

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.mfbz.cn/a/883902.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++笔试强训】如何成为算法糕手Day3

​ 学习编程就得循环渐进&#xff0c;扎实基础&#xff0c;勿在浮沙筑高台 循环渐进Forward-CSDN博客 目录 循环渐进Forward-CSDN博客 第一题&#xff1a;除2&#xff01; 第二题&#xff1a;dd爱框框 第三题&#xff1a;简写单词 第一题&#xff1a;除2&#xff01; 牛客网…

数据保护从现在开始:如何抵御 .[RestoreBackup@cock.li].SRC 勒索病毒

导言 勒索病毒是一种不断演变的网络威胁&#xff0c;.[RestoreBackupcock.li].SRC、[chewbaccacock.li].SRC勒索病毒便是其中一种新型的攻击手段。该病毒通过加密用户文件并要求支付赎金来恢复访问&#xff0c;给个人和企业带来了严重的安全风险和经济损失。本文91数据恢复将探…

25 基于51单片机的温度电流电压检测系统(压力、电压、温度、电流、LCD1602)

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机&#xff0c;通过DS18B20检测温度&#xff0c;滑动变阻器连接数模转换器模拟电流、电压&#xff0c;通过LCD1602显示&#xff0c;程序里设置温度阈值为40&#xff0c;电流阈值为60&am…

新版torch_geometric不存在uniform、maybe_num_nodes函数问题(Prune4ED论文报错解决)

这是在复现论文“Towards accurate subgraph similarity computation via neural graph pruning”时遇到的报错。 ImportError: cannot import name uniform from torch_geometric.nn.pool.topk_pool 一、报错原因 论文作者使用的是2.1.0版本的torch_geometric。而我安装了2.…

[vulnhub] Jarbas-Jenkins

靶机链接 https://www.vulnhub.com/entry/jarbas-1,232/ 主机发现端口扫描 扫描网段存活主机&#xff0c;因为主机是我最后添加的&#xff0c;所以靶机地址是135的 nmap -sP 192.168.75.0/24 // Starting Nmap 7.93 ( https://nmap.org ) at 2024-09-21 14:03 CST Nmap scan…

linux信号| 学习信号三步走 | 学习信号需要打通哪些知识脉络?

前言: 本节内容主要讲解linux下信号的预备知识以及信号的概念&#xff0c; 信号部分我们将会分为几个阶段进行讲解&#xff1a;信号的概念&#xff0c; 信号的产生&#xff0c; 信号的保存。本节主要讲解信号 ps:本节内容适合学习了进程相关概念的友友们进行观看哦 目录 什么是…

教练车一键启动应用‌案例

教练车一键启动应用‌主要提供了便捷的车辆启动方式&#xff0c;通过一个按钮实现车辆的启动和熄火&#xff0c;简化了传统的打火过程。这种智能配置不仅提升了车辆的科技感&#xff0c;还增加了市场竞争力。一键启动系统可以在原车钥匙锁头位置安装&#xff0c;也可以作为独立…

基于JAVA+SpringBoot+Vue的疫苗发布和接种预约系统

基于JAVASpringBootVue的疫苗发布和接种预约系统 前言 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末附源码下载链接&#x1f3…

3D 模型GLTF、GLB格式文件介绍使用;FBX格式

一、GLTF、GLB介绍 GLTF&#xff08;GL Transmission Format&#xff09;和 GLB&#xff08;GL Binary&#xff09;是用于在 Web 和各种应用程序中传输和加载 3D 场景和模型的开放标准格式。它们由 Khronos Group 开发&#xff0c;旨在提供一种高效、可扩展且易于使用的 3D 内…

URI和URL的区别

1: 将 URI 转换为 URL import java.net.URI; import java.net.URL;public class UriToUrlExample {public static void main(String[] args) {// 创建一个 URI 对象URI uri = new URI("http://example.com/path/to/resource");// 将 URI 转换为 URLtry {URL url = u…

推荐一款PS VR2电脑PC适配器 / 转接板方案

一、引言 随着虚拟现实技术的不断发展&#xff0c;PS VR2 为用户带来了沉浸式的游戏和娱乐体验。然而&#xff0c;为了让 PS VR2 能够与电脑连接&#xff0c;充分发挥其性能并拓展使用场景&#xff0c;需要开发一款电脑适配器 / 转接板。本技术文档方案旨在详细阐述该适配器 / …

【伺服】Servo入坑学习记录①

前言 这是一个自我摸索的过程&#xff0c;如果有什么良好的、或严厉的批评和建议&#xff0c;恳请指教&#xff0c; 万分感谢经典控制理论中&#xff0c;有几个重要的概念和工具&#xff0c;用于分析和设计控制系统。以下是对 传递函数、伯德图、奈奎斯特图、稳定裕度 和 带宽 …

缓存装饰器@cached_property

这个装饰器好像在好多包里都有&#xff0c;我在阅读源码的过程中&#xff0c;transformers.utils也有这个。查阅资料&#xff0c;大体上了解了它的用法。参考&#xff1a;[python]cached_property缓存装饰器 - faithfu - 博客园 这个装饰器用在类里面的某个方法前面&#xff0…

传奇微端黑屏不更新地图?传奇微端架设教程——GOM引擎

登录器和网站配置好后&#xff0c;我们进入游戏后会发现是黑屏的&#xff0c;更新不了地图和NPC这些&#xff0c;因为还没有做微端&#xff0c;会黑屏也是正常的。有些老G做了微端但是还是黑屏&#xff0c;就可能是你的微端架设出现了问题&#xff0c;可以参考以下教程。 gom引…

将图片资源保存到服务器的盘符中

服务类 系统盘符&#xff1a;file-path.disk&#xff08;可能会变&#xff0c;配置配置文件dev中&#xff09;文件根路径&#xff1a;file-path.root-path&#xff08;可能会变&#xff0c;配置配置文件dev中&#xff09;http协议的Nginx的映射前缀&#xff1a;PrefixConstant.…

Dos.ORM简单说明

1 下载Dos.Tools-master 地址&#xff1a;Dos.Tool: 实体生成工具&#xff0c;成熟轻量级ORM、上手简单、性能高、功能强大&#xff01; 2 Dos.ORM仅支持DbFirst模式&#xff0c;即必须先有数据库&#xff0c;这里以Sql Server为例 3 新建项目&#xff0c;添加引用Dos.ORM.dll&…

C语言编译和链接详解(通俗易懂,深入本质)

我们平时所说的程序,是指双击后就可以直接运行的程序,这样的程序被称为可执行程序(Executable Program)。在 Windows 下,可执行程序的后缀有.exe和.com(其中.exe比较常见);在类 UNIX 系统(Linux、Mac OS 等)下,可执行程序没有特定的后缀,系统根据文件的头部信息来判…

物联网助力智慧交通:优势与前景

智慧交通是当今城市发展的必然趋势&#xff0c;而物联网技术在交通运输领域的应用正是为实现智慧交通建设提供了前所未有的机遇和优势。物联网作为连接和控制物理世界的重要技术手段&#xff0c;在交通领域的应用极大地改善了交通系统的效率、安全性和环保性。 首先&#xff0c…

【华为】用策略路由解决双出口运营商问题

需求描述 不同网段访问互联网资源时&#xff0c;走不同的出口&#xff0c;即PC1走电信出口&#xff0c;PC2走移动出口。 客户在内网接口下应用策略路由后往往出现无法访问内网管理地址的现象&#xff0c;该举例给出解决办法。 拓扑图 基础配置 #sysname R1 # # interface G…

UE虚幻引擎云渲染汽车动画的优势!

在汽车广告和动画制作领域&#xff0c;虚幻引擎&#xff08;UE&#xff09;结合云渲染技术正掀起一场技术革命。这项技术以其高性能、成本效益和灵活性&#xff0c;为创作者提供了强大的工具&#xff0c;以实现更加逼真和高效的汽车动画制作。 一、为什么选择UE虚幻引擎制作汽车…