C++二叉树进阶

1.二叉搜索树

1.1二叉搜索树概念

二叉搜索树又称二叉排序树,它或者是一颗空树,或者具有以下性质的二叉树

  • 若它的左子树不为空,则左子树上所有结点的值小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树
    在这里插入图片描述

1.2二叉搜索树操作

在这里插入图片描述

int a[] = {8, 3, 1, 10, 6, 4, 7, 14, 13};

1.二叉搜索树的查找

  • a. 从根开始比较,查找,比根大则往右边查找,比根小则往左边查找
  • b. 最多查找高度次,走到空,还没找到,这个值不存在

2.二叉搜索树的插入
插入的具体过程如下:

  • a. 树为空,则直接新增节点,赋值给root指针
  • b. 树不为空,按二叉搜索树性质查找插入位置,插入新节点
    在这里插入图片描述
    1.二叉搜索树的删除
    首先查找元素是否在二叉搜索树中,如果不存在,则返回,否则要删除的结点可能分下面四种情况
  • a. 要删除的结点无孩子结点
  • b. 要删除的结点只有左孩子结点
  • c. 要删除的结点只有右孩子结点
  • d. 要删除的结点有左,右孩子结点

看起来有待删除节点有四种情况,实际情况a可以与情况b或c合并起来,因此真正的删除情况如下

  • 情况b: 删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点-直接删除
  • 情况c: 删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点_直接删除
  • 情况d: 在它的右子树中寻找中序下的第一个节点(关键码最小),用它的值填补到被删除节点中,再来处理该节点的删除问题_替换法删除
    在这里插入图片描述

1.3二叉搜索树的实现

template<class T>
struct BSTNode
{BSTNode(const T& data = T()): _pLeft(nullptr) , _pRight(nullptr), _data(data){}BSTNode<T>* _pLeft;BSTNode<T>* _pRight;T _data;
};
template<class T>
class BSTree
{typedef BSTNode<T> Node;typedef Node* PNode;
public:BSTree(): _pRoot(nullptr){}~BSTree();// 根据二叉搜索树的性质查找:找到值为data的节点在二叉搜索树中的位置PNode Find(const T& data);bool Insert(const T& data){// 如果树为空,直接插入if (nullptr == _pRoot){_pRoot = new Node(data);return true;}// 按照二叉搜索树的性质查找data在树中的插入位置PNode pCur = _pRoot;// 记录pCur的双亲,因为新元素最终插入在pCur双亲左右孩子的位置PNode pParent = nullptr;while (pCur){pParent = pCur;if (data < pCur->_data)pCur = pCur->_pLeft;else if (data > pCur->_data)pCur = pCur->_pRight;  // 元素已经在树中存在elsereturn false;}// 插入元素pCur = new Node(data);if (data < pParent->_data)pParent->_pLeft = pCur;elsepParent->_pRight = pCur;return true;}bool Erase(const T& data){// 如果树为空,删除失败if (nullptr == _pRoot)return false;// 查找在data在树中的位置PNode pCur = _pRoot;PNode pParent = nullptr;while (pCur){if (data == pCur->_data)break;else if (data < pCur->_data){pParent = pCur;pCur = pCur->_pLeft;}else{pParent = pCur;pCur = pCur->_pRight;}}// data不在二叉搜索树中,无法删除if (nullptr == pCur)return false;// 分以下情况进行删除if (nullptr == pCur->_pRight){// 当前节点只有左孩子或者左孩子为空---可直接删除}else if (nullptr == pCur->_pRight){// 当前节点只有右孩子---可直接删除}else{// 当前节点左右孩子都存在,直接删除不好删除,可以在其子树中找一个替代结点,比如:// 找其左子树中的最大节点,即左子树中最右侧的节点,或者在其右子树中最小的节//点,即右子树中最小的节点// 替代节点找到后,将替代节点中的值交给待删除节点,转换成删除替代节点}return true;}void InOrder();
private:PNode _pRoot;
};

1.4二叉搜索树的应用

1.k模型:k模型即只有key作为关键码,结构中只需要存储key即可,关键码即为需要搜索到的值
比如:给一个单词word,判断该单词是否拼写正确,具体方式如下

  • 以词库只不过所有单词集合中的每个单词作为key,构建一颗二叉搜索树
  • 在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误

2.kv模型:每一个关键码key,都有与之对应的值value,即<key, value>的键值对,该种方式在现实生活中非常常见

  • 比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英文的单词与其对应的中文<word, Chinese >就构成一种键值对
  • 再比如统计单词次数,统计成功后,给定单词就可以快速找到其出现的次数,单词与其出现次数就是<word, count>就构成一种键值对
// 改造二叉搜索树为KV结构
template<class K, class V>
struct BSTNode{BSTNode(const K& key = K(), const V& value = V()): _pLeft(nullptr) , _pRight(nullptr), _key(key), _Value(value){}BSTNode<T>* _pLeft;BSTNode<T>* _pRight;K _key;V _value;};
template<class K, class V>
class BSTree{typedef BSTNode<K, V> Node;typedef Node* PNode;
public:BSTree(): _pRoot(nullptr){}PNode Find(const K& key);bool Insert(const K& key, const V& value)bool Erase(const K& key)
private:PNode _pRoot;};
void TestBSTree3()
{// 输入单词,查找单词对应的中文翻译BSTree<string, string> dict;dict.Insert("string", "字符串");dict.Insert("tree", "树");dict.Insert("left", "左边、剩余");dict.Insert("right", "右边");dict.Insert("sort", "排序");// 插入词库中所有单词string str;while (cin>>str){BSTreeNode<string, string>* ret = dict.Find(str);if (ret == nullptr){cout << "单词拼写错误,词库中没有这个单词:" <<str <<endl;}else{cout << str << "中文翻译:" << ret->_value << endl;}}
}
void TestBSTree4()
{// 统计水果出现的次数string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };BSTree<string, int> countTree;for (const auto& str : arr){// 先查找水果在不在搜索树中// 1、不在,说明水果第一次出现,则插入<水果, 1>// 2、在,则查找到的节点中水果对应的次数++//BSTreeNode<string, int>* ret = countTree.Find(str);auto ret = countTree.Find(str);if (ret == NULL){countTree.Insert(str, 1);}else{ret->_value++;}}countTree.InOrder();
}

2.5二叉搜索树的性能分析

插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能

对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多

但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树
在这里插入图片描述
最优情况下,二叉搜索树为完全二叉树(或者接近完全二叉树),其平均比较次数为:O(logn)
最差情况下,二叉搜索树退化为单支树(或者类似单支),其平均比较次数为O(n)

问题:如果退化成单支树,二叉搜索树的性能就失去了,那能否改进,不论按照什么次序插入关键码,二叉搜索树的性能都能达到最优
1. 平衡二叉搜索树(AVL树)

  • 基本思想:AVL树是一种自平衡的二叉搜索树,它在插入或删除节点时,会通过旋转操作来保持树的平衡。
    它定义了一个平衡因子(Balance Factor),对于树中的每个节点,平衡因子是其左子树高度与右子树高度之差。平衡因子的取值只能是 -1、0 或 1。如果某个节点的平衡因子绝对值大于1,就需要通过旋转操作来调整树的结构,使其重新达到平衡。

  • 性能分析:AVL树通过不断地调整树的结构来保持平衡,使得树的高度始终保持在 O(logn)​ 的范围内,其中 n​ 是树中节点的数量。因此,无论插入节点的顺序如何,AVL树的查找、插入和删除操作的时间复杂度都能保持在 O(logn)​,性能相对稳定。

2. 红黑树

  • 基本思想:红黑树是一种自平衡的二叉搜索树,它通过对节点颜色的限制和调整来保持树的平衡。
    红黑树中的每个节点都有一个颜色属性,要么是红色,要么是黑色。并且满足以下性质:

    • 每个节点要么是红色,要么是黑色。
    • 根节点是黑色。
    • 每个叶子节点(NIL节点,空节点)是黑色。
    • 如果一个节点是红色,则它的两个子节点都是黑色。
    • 从任意一个节点到其每个叶子节点的所有路径上包含相同数目的黑色节点。
  • 性能分析:红黑树通过对节点颜色的限制和调整,保证了树的高度始终保持在 O(logn)​ 的范围内。因此,无论插入节点的顺序如何,红黑树的查找、插入和删除操作的时间复杂度都能保持在 O(logn)​,性能相对稳定。而且,红黑树的调整操作相对AVL树来说更加灵活,在实际应用中可能具有更好的性能表现。

3. 伸展树(Splay Tree

  • 基本思想:伸展树是一种自适应的二叉搜索树,它的基本思想是在每次访问一个节点后,通过一系列的旋转操作将该节点移动到根节点的位置,使得最近被访问的节点更容易被再次访问。
    伸展操作(Splaying)是伸展树的核心操作,它通过一系列的旋转操作将指定节点移动到根节点。伸展操作有多种实现方式,常见的有自底向上的伸展和自顶向下的伸展。

  • 性能分析:虽然伸展树不能保证在任何情况下树的高度都保持在 O(logn)​,但从均摊分析的角度来看,伸展树的操作时间复杂度为 O(logn)​。也就是说,在一系列操作中,平均每次操作的时间复杂度是对数级别的。因此,在实际应用中,伸展树也能够提供较好的性能。

虽然这些改进的数据结构可以在很大程度上避免二叉搜索树退化为单支树,提高性能的稳定性,但在某些极端情况下,仍然可能存在性能波动。例如,在AVL树和红黑树中,频繁的插入和删除操作可能会导致频繁的调整操作,影响性能;在伸展树中,如果访问模式非常不规则,也可能导致树的结构变得不平衡。

3.二叉树进阶题

这些题目更适合使用C++完成,难度也更大一些
1. 二叉树创建字符串
2. 二叉树的分层遍历1
3. 二叉树的分层遍历2
4. 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先5. 二叉树搜索树转换成排序双向链表
6. 根据一棵树的前序遍历与中序遍历构造二叉树
7. 根据一棵树的中序遍历与后序遍历构造二叉树
8. 二叉树的前序遍历,非递归迭代实现
9. 二叉树中序遍历 ,非递归迭代实现
10. 二叉树的后序遍历 ,非递归迭代实现

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

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

相关文章

亲测有效!解决PyCharm下PyEMD安装报错 ModuleNotFoundError: No module named ‘PyEMD‘

解决PyCharm下PyEMD安装报错 PyEMD安装报错解决方案 PyEMD安装报错 PyCharm下通过右键自动安装PyEMD后运行报错ModuleNotFoundError: No module named ‘PyEMD’ 解决方案 通过PyCharm IDE python package搜索EMD-signal&#xff0c;选择版本后点击“install”执行安装

2. Java-MarkDown文件解析-工具类

2. Java-MarkDown文件解析-工具类 1. 思路 读取markdown文件的内容&#xff0c;根据markdown的语法进行各个类型语法的解析。引入工具类 commonmark 和 commonmark-ext-gfm-tables进行markdown语法解析。 2. 工具类 pom.xml <!-- commonmark 解析markdown --> <d…

常用符号的英语表达

plus 加号&#xff1b;正号 -  minus 减号&#xff1b;负号  plus or minus 正负号  is multiplied by 乘号  is divided by 除号 &#xff1d; is equal to 等于号 ≠ is not equal to 不等于号 ≡ is equivalent to 全等于号 ≌ is equal to or approximatel…

青少年编程与数学 02-008 Pyhon语言编程基础 02课题、基础概念

青少年编程与数学 02-008 Pyhon语言编程基础 02课题、基础概念 一、标识符二、关键字三、字面量四、变量五、运算符1. 算术运算符2. 比较运算符3. 逻辑运算符4. 赋值运算符5. 成员运算符6. 身份运算符 六、表达式七、语句八、注释单行注释多行注释文档字符串&#xff08;Docstr…

lanqiaoOJ 2145:求阶乘 ← 二分法

【题目来源】 https://www.lanqiao.cn/problems/2145/learning/ 【题目描述】 满足 N&#xff01;的末尾恰好有 K 个 0 的最小的 N 是多少&#xff1f; 如果这样的 N 不存在输出 -1。 【输入格式】 一个整数 K。 【输出格式】 一个整数代表答案。 【输入样例】 2 【输出样…

vs2013 使用 eigen 库编译时报 C2059 错的解决方法

&#xff08;个人感觉&#xff09;vs2013 就不能使用版本大于等于 3.4 的 eigen&#xff0c;使用 3.3.9 就可以了&#xff0c;再不行就用 3.3.8 另一个博主也遇到过用 vs2013 的时候不能编译 3.4 的 eigen 的问题&#xff0c;不过我用的是 win11&#xff0c;所以感觉跟操作系统…

U盘打开提示格式化:深度解析与数据恢复全攻略

在数字化时代&#xff0c;U盘作为便捷的数据存储和传输工具&#xff0c;广泛应用于各个领域。然而&#xff0c;当我们满怀期待地插入U盘&#xff0c;却遭遇“U盘打开提示格式化”的尴尬局面时&#xff0c;那份焦虑与无助感油然而生。本文将全面剖析U盘打开提示格式化的原因、应…

智能工厂能耗管理:Python助力节能增效

智能工厂能耗管理:Python助力节能增效 在工业4.0时代,工厂能耗管理已成为制造企业降本增效的重要一环。传统的能耗管理方式往往依赖人工统计和经验决策,导致能源浪费严重。而借助人工智能与Python的强大能力,我们可以实现智能化、数据驱动的能耗优化方案。今天,我们就来聊…

MyBatis 框架:简化 Java 数据持久化的利器

Java学习资料 Java学习资料 Java学习资料 一、引言 在 Java 企业级应用开发中&#xff0c;数据持久化是一个至关重要的环节&#xff0c;它涉及到将应用程序中的数据保存到数据库&#xff0c;以及从数据库中读取数据供应用程序使用。传统的 JDBC 编程虽然可以实现数据持久化&…

[NOI1995] 石子合并

[NOI1995] 石子合并 题目描述 在一个圆形操场的四周摆放 N N N 堆石子&#xff0c;现要将石子有次序地合并成一堆&#xff0c;规定每次只能选相邻的 2 2 2 堆合并成新的一堆&#xff0c;并将新的一堆的石子数&#xff0c;记为该次合并的得分。 试设计出一个算法,计算出将 …

未来无线技术的发展方向

未来无线技术的发展趋势呈现出多样化、融合化的特点&#xff0c;涵盖速度、覆盖范围、应用领域、频段利用、安全性等多个方面。这些趋势将深刻改变人们的生活和社会的运行方式。 传输速度提升&#xff1a;Wi-Fi 技术迭代加快&#xff0c;如 Wi-Fi7 理论峰值速率达 46Gbps&#…

HTB:Forest[WriteUP]

连接至HTB服务器并启动靶机 分配IP&#xff1a;10.10.16.21 靶机IP&#xff1a;10.10.10.161 靶机Domain&#xff1a;forest.htb 目录 连接至HTB服务器并启动靶机 信息收集 使用rustscan对靶机TCP端口进行开放扫描 将靶机TCP开放端口号提取并保存 使用nmap对靶机TCP开放端…

芯片AI深度实战:实战篇之vim chat

利用vim-ollama这个vim插件&#xff0c;可以在vim内和本地大模型聊天。 系列文章&#xff1a; 芯片AI深度实战&#xff1a;基础篇之Ollama-CSDN博客 芯片AI深度实战&#xff1a;基础篇之langchain-CSDN博客 芯片AI深度实战&#xff1a;实战篇之vim chat-CSDN博客 芯片AI深度…

JavaScript - Web APIs(下)

日期对象 目标&#xff1a;掌握日期对象&#xff0c;可以让网页显示日期 日期对象&#xff1a;用来表示时间的对象 作用&#xff1a;可以得到当前系统时间 学习路径&#xff1a; 实例化 日期对象方法 时间戳 实例化 目标&#xff1a;能够实例化日期对象 在代码中发…

selenium自动化测试框架——面试题整理

目录 1. 什么是 Selenium&#xff1f;它的工作原理是什么&#xff1f; 2. Selenium 主要组件 3. 常见 WebDriver 驱动 4. Selenium 如何驱动浏览器&#xff1f; 5. WebDriver 协议是什么&#xff1f; 6. Page Object 模式与 Page Factory 7. 如何判断元素是否可见&#x…

【安全测试】测开方向学习遇到的问题记录

【问题一】springboot如何访问静态资源文件 springboot启动根路径位置 F:\untitled05\demo4\src\main\resources\static 例如图片位置存放在F:\untitled05\demo4\src\main\resources\static即可 配置文件配置 spring.web.resources.static-locationsfile:/F:/untitled05/de…

Unity|小游戏复刻|见缝插针2(C#)

控制针的运动 新建一个Pin脚本 将Pin脚本拖到针Pin的下面 保存代码 using UnityEngine;public class Pin : MonoBehaviour {public float speed 5;private bool isFly false;private bool isReach false;private Transform startPosition;// Start is called once bef…

2025年数学建模美赛 A题分析(3)楼梯使用方向偏好模型

2025年数学建模美赛 A题分析&#xff08;1&#xff09;Testing Time: The Constant Wear On Stairs 2025年数学建模美赛 A题分析&#xff08;2&#xff09;楼梯磨损分析模型 2025年数学建模美赛 A题分析&#xff08;3&#xff09;楼梯使用方向偏好模型 2025年数学建模美赛 A题分…

DeepSeek大模型技术解析:从架构到应用的全面探索

一、引言 在人工智能领域&#xff0c;大模型的发展日新月异&#xff0c;其中DeepSeek大模型凭借其卓越的性能和广泛的应用场景&#xff0c;迅速成为业界的焦点。本文旨在深入剖析DeepSeek大模型的技术细节&#xff0c;从架构到应用进行全面探索&#xff0c;以期为读者提供一个…

「AI学习笔记」深度学习的起源与发展:从神经网络到大数据(二)

深度学习&#xff08;DL&#xff09;是现代人工智能&#xff08;AI&#xff09;的核心之一&#xff0c;但它并不是一夜之间出现的技术。从最初的理论提出到如今的广泛应用&#xff0c;深度学习经历了几乎一个世纪的不断探索与发展。今天&#xff0c;我们一起回顾深度学习的历史…