【数据结构】二叉搜索(查找/排序)树

一、二叉搜索树基本概念

1、定义

二叉搜索树,又称为二叉排序树二叉查找树,它满足如下四点性质:

1)空树是二叉搜索树;
2)若它的左子树不为空,则左子树上所有结点的值均小于它根结点的值;
3)若它的右子树不为空,则右子树上所有结点的值均大于它根结点的值;
4)它的左右子树均为二叉搜索树;

 如上图所示:二叉搜索树的任何一棵子树,它的根结点的值一定大于左子树所有结点的值,且一定小于右子树所有结点的值。如果对二叉搜索树进行中序遍历,我们可以发现,得到的序列是一个递增序列,上述的遍历结果为[1,2,3,4,5,6,7,8]。

如果要查找4,只需要从根结点比较查找3次就能找到,可以显著提高搜索的速度

二、二叉搜索树基础操作

1、查找算法

(1)查找原理

在二叉搜索树中查找某个数是否存在,存在返回 true,不存在返回 false

对于要查找的数 val ,从根结点出发,总共四种情况依次判断:

1)若二叉搜索树为空树,直接返回 false;

2) val 的值 等于 树根结点的值,则直接返回 true;

3) val 的值 小于 树根结点的值,说明 val 对应的结点不在根结点,也不在右子树上,需要在左子树上查找,递归返回左子树的查找结果;

4) val 的值 大于 树根结点的值,说明 val 对应的结点不在根结点,也不在左子树上,需要在右子树上查找,递归返回右子树的查找结果;

(2)查找算法源码

① 结点源码

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

② 查找算法源码 (深度优先,递归查找)

bool BSTFind(TreeNode* root, int val) 
{if (root == nullptr) {return false;}if (root->val == val) {return true;}if (val < root->val) {return BSTFind(root->left, val);}else {return BSTFind(root->right, val);}
}

2、插入算法

(1)插入原理

将给定的值 val 生成结点后,插入到树上的某个位置,并且保持这棵树还是二叉搜索树。对于要插入的值 val ,从根结点出发,总共四种情况依次判断:

1)若为空树,则创建一个值为 val 的结点并且返回根结点;

2) val 的值 等于 树根结点的值,无须执行插入,直接返回根结点;

3) val 的值 小于 树根结点的值,那么插入位置一定在 左子树,递归执行插入左子树的过程,并且返回插入结果作为新的左子树

4) val 的值 大于 树根结点的值,那么插入位置一定在 右子树,递归执行插入右子树的过程,并且返回插入结果作为新的右子树

(2) 插入源码

TreeNode* BSTInsert(TreeNode* root, int val) {if (root == nullptr) {root = new TreeNode(val);return root;}if (val == root->val) {return root;}if (val < root->val) {root->left = BSTInsert(root->left, val);}else {root->right = BSTInsert(root->right, val);}return root;
}

3、删除算法

(1)删除原理

删除值为 val 结点,从根结点出发,总共四种情况依次判断:

1)空树,不存在结点直接返回空树;

2) val 的值 小于 树根结点的值,则需要删除的结点一定不在右子树上,递归调用删除左子树的对应结点;

3) val 的值 大于 树根结点的值,则需要删除的结点一定不在左子树上,递归调用删除右子树的对应结点;

4) val 的值 等于 树根结点的值,相当于是要删除根结点,这时候又要分三种情况:

  • 当前树只有左子树,则直接将左子树返回,并且释放当前树根结点的空间;
  • 当前树只有右子树,则直接将右子树返回,并且释放当前树根结点的空间;
  • 当左右子树都存在时,需要在右子树上找到一个值最小的结点,替换新的树根,而其它结点组成的树作为它的子树;

(2)删除源码

由上述删除算法原理可知,删除结点之前可能还需要找最小结点,所以需要定义查找最小结点接口

TreeNode* BSTFindMin(TreeNode* root) {  while (root && root->left)  {root = root->left;  }     return root;                  
}

查找根为 root ,值最小的那个结点的值,根据二叉搜索树的性质,如果左子树存在,则必然存在更小的值,递归搜索左子树,且最小值结点为叶子结点;如果左子树不存在,则根结点的值必然最小,直接返回。

删除根结点,并返回新根结点

//删除根结点并返回新根结点
TreeNode* Delete(TreeNode* root) {TreeNode* delNode=nullptr, * retNode=nullptr;if (!root) {                             //空树,直接返回空return nullptr;}if (root->left == nullptr) {  //只有右子树(包含单结点),删除根空间后返回右子树根结点delNode = root;retNode = root->right;delete delNode;}else if (root->right == nullptr) {   //只有左子树,删除根空间后返回左子树根结点delNode = root;retNode = root->left;delete delNode;}else {retNode = root;TreeNode* cur = root->right;TreeNode* pcur = root;while (cur->left){pcur = cur;cur = cur->left;}delNode = cur;retNode->val = cur->val;if (pcur->left == cur) {//右子树的最小值在右子树的左子树上pcur->left = cur->right;}else {//右子树的最小值为右子树的根pcur->right = cur->right;}delete delNode;}return retNode;
}
  • 如果左子树为空,则用右子树做为新的树根;
  • 如果右子树为空,则用左子树作为新的树根;
  • 否则,当左右子树都为非空时,从右子树上找出最小的结点,它的值作为根的新值,并删除这个最小结点。

删除指定值的结点

//删除指定结点
TreeNode* BSTDelete(TreeNode* root, int val) {if (nullptr == root) {return nullptr;                                  }if (val == root->val) {return Delete(root);                          }else if (val < root->val) {root->left = BSTDelete(root->left, val);      }else if (val > root->val) {root->right = BSTDelete(root->right, val);    }return root;                                      
}
  • 如果为空树,则直接返回空结点;
  • 如果需要删除的结点的值 等于 树根结点的值,则直接调用接口 Delete ;
  • 如果需要删除的结点的值 小于 树根结点的值,则需要删除的结点必定在左子树上,递归调用左子树的删除,并且将返回值作为新的左子树的根结点;
  •  如果需要删除的结点的值 大于 树根结点的值,则需要删除的结点必定在右子树上,递归调用右子树的删除,并且将返回值作为新的右子树的根结点;
  • 返回当前树的根结点;

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一文详解动态 Schema

在数据库中&#xff0c;Schema 常有&#xff0c;而动态 Schema 不常有。 例如&#xff0c;SQL 数据库有预定义的 Schema&#xff0c;但这些 Schema 通常都不能修改&#xff0c;用户只有在创建时才能定义 Schema。Schema 的作用是告诉数据库使用者所希望的表结构&#xff0c;确保…

Docker资源配额

Docker资源配额指的是对Docker容器或服务在系统资源使用方面的限制。 通过资源配额&#xff0c;可以控制和限制Docker容器可以使用的CPU、内存、磁盘空间和网络带宽等资源。 根据应用程序的需求和系统环境来设置适当的资源配额&#xff1a;过于严格的配额可能导致应用程序性能下…

05、Kafka ------ CMAK 各个功能的作用解释(主题和分区 详解,用命令行和图形界面创建主题和查看主题)

目录 CMAK 各个功能的作用解释&#xff08;主题&#xff09;★ 主题★ 分区★ 创建主题&#xff1a;★ 列出和查看主题 CMAK 各个功能的作用解释&#xff08;主题&#xff09; ★ 主题 Kafka 主题虽然也叫 topic&#xff0c;但它和 Pub-Sub 消息模型中 topic 主题及 AMQP 的 t…

专业课130+,总分390+四川大学951信号与系统考研通信,电子信息经验分享

今年专业课130&#xff0c;总分390&#xff0c;顺利上岸&#xff0c;将近一年复习一路走来&#xff0c;感慨很多&#xff0c;希望以下经历可以给后来的同学提供一些参考。 初试备考经验 公共课&#xff1a;三门公共课&#xff0c;政治&#xff0c;英语&#xff0c;数学。在备…

药品销售管理系统

一、系统总体设计 该系统是针对医药销售行业所设计&#xff0c;主要用来管理销售药品所产生的额大量信息。该系统可帮助从医人员便捷管理药品销售信息&#xff0c;极大的提高工作效率&#xff0c;降低人工操作的失误率&#xff0c;为药品的销售者和购买者提供便利。根据对需求的…

astadmin安装querylist插件Puppeteer

我本来是想在linux服务器上安装&#xff0c;折腾了一天也没安装成功&#xff0c;由于急着用&#xff0c;就先做window10上安装了&#xff0c;以后有时间再研究centos7上安装 一 首先需要安装fastadmin 框架和querylist插件 这个大家可以自行安装&#xff0c;querylist安装地址…

AI硬件2——SIPEED MaixCube(Kendryte K210)基础使用

系列文章目录 官方网站 开发文档 文章目录 系列文章目录前言一、特点介绍1、MaixPy2、KPU3、MaixPy IDE4、kmodel 二、环境准备1、USB 驱动安装1&#xff09;Linux2&#xff09;Windows 2、更新固件3、串口工具1&#xff09;连接硬件2&#xff09;Windows串口工具3&#xff09…

PHP进阶-实现网站的QQ授权登录

授权登录是站点开发常见的应用场景&#xff0c;通过社交媒体一键授权可以跳过注册站点账户的繁琐操作。本文将讲解如何用PHP实现QQ授权登录。首先&#xff0c;我们需要申请QQ互联开发者账号获得APPID和密钥&#xff1b;接着&#xff0c;我们下载QQ官方SDK&#xff1a;PHP SDK v…

电商API-获取拼多多商品详情数据精准价格API测试示例

pinduoduo.item_get_app_pro获取拼多多商品详情数据 如何获取apikey&#xff1f; 公共参数 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地址中&#xff…

20 太空漫游

效果演示 实现了一个太空漫游的动画效果&#xff0c;其中包括火箭、星星和月亮。当鼠标悬停在卡片上时&#xff0c;太阳和星星会变成黄色&#xff0c;火箭会变成飞机&#xff0c;月亮会变成小型的月亮。整个效果非常炫酷&#xff0c;可以让人想起科幻电影中的太空漫游。 Code &…

淘宝商品详情API接口(item_get-获得淘宝商品详情)主图,属性,sku,价格,搜索商品列表

淘宝开放平台提供了API接口&#xff0c;允许开发者获取淘宝商品的相关信息。为了获取商品详情&#xff0c;您可以使用 item_get API接口。以下是如何使用此API接口来获取商品的主图、属性、SKU、价格以及搜索商品列表的简要说明&#xff1a; 公共参数 名称类型必须描述keyStr…

面试之线程状态

1.线程有哪些状态 1.1Java线程的六种状态 Java 线程六种状态 新建 当一个线程对象被创建&#xff0c;但还未调用 start 方法时处于新建状态 此时未与操作系统底层线程关联 可运行 调用了 start 方法&#xff0c;就会由新建进入可运行 此时与底层线程关联&#xff0c;由操作…