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.rhkb.cn/news/9314.html

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

相关文章

“AI视频智能分析系统:让每一帧视频都充满智慧

嘿&#xff0c;大家好&#xff01;今天咱们来聊聊一个特别厉害的东西——AI视频智能分析系统。想象一下&#xff0c;如果你有一个超级聪明的“视频助手”&#xff0c;它不仅能自动识别视频中的各种元素&#xff0c;还能根据内容生成详细的分析报告&#xff0c;是不是感觉特别酷…

神经网络|(五)概率论基础知识-条件概率

【1】引言 前序完成了古典概型知识的简单学习&#xff0c;今天在此基础上开始条件概率的学习。古典概型的学习文章为&#xff1a;神经网络|(四)概率论基础知识-古典概型-CSDN博客 【2】条件概率 条件概率就是在A事件已经发生的条件下&#xff0c;B事件发生的概率。 设A、B是…

分布式版本控制系统:Git

1 Git概述 Git官网&#xff1a;https://git-scm.com/ Git是一个免费的、开源的分布式版本控制系统&#xff0c;可以快速高效地处理从小型到大型的各种项目Git易于学习&#xff0c;占地面积小&#xff0c;性能极快。它具有廉价的本地库、方便的暂存区域和多个工作流分支等特性…

【leetcode】T1599

解题心得&#xff1a; 题目长且绕&#xff0c;直接看测试样例的解析有助于更快把握题目核心需求&#xff08;即关注样例的输入、运算逻辑、输出&#xff09; 题面 原题链接1599. 经营摩天轮的最大利润 - 力扣&#xff08;LeetCode&#xff09; AC代码 class Solution { pub…

能说说MyBatis的工作原理吗?

大家好&#xff0c;我是锋哥。今天分享关于【Redis为什么这么快?】面试题。希望对大家有帮助&#xff1b; 能说说MyBatis的工作原理吗&#xff1f; MyBatis 是一款流行的持久层框架&#xff0c;它通过简化数据库操作&#xff0c;帮助开发者更高效地与数据库进行交互。MyBatis…

Oracle Primavera P6 最新版 v24.12 更新 1/2

目录 引言 P6 PPM 更新内容 1. 在提交更新基线前预览调整 2. 快速轻松地取消链接活动 3. 选择是否从 XER 文件导入责任经理 4. 提高全局变更报告的清晰度 5. 将整个分层代码值路径导出到 CPP 6. 里程碑活动支持所有关系类型 6. 时间表批准 7. 性能改进 8. 安装改进 …

ORA-04031 错误

ORA-04031 错误表示 Oracle 数据库无法在共享池中分配所需的内存。共享池是 SGA&#xff08;系统全局区&#xff09;的一部分&#xff0c;用于缓存SQL语句、PL/SQL存储过程和控制结构等。此错误通常与数据库的内存管理有关&#xff0c;可能由于共享池大小不足或存在内存碎片导致…

SpringBoot 中的测试jar包knife4j(实现效果非常简单)

1、效果图 非常快的可以看见你实现的接口 路径http://localhost:8080/doc.html#/home 端口必须是自己的 2、实现效果 2.1、导入jar包 <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-openapi3-jakarta-spring-boot-star…

2024年记 | 凛冬将至

放弃幻想&#xff0c;准备斗争&#xff01; 考研or就业&#xff1f; 上大学以来&#xff0c;考研上名校在我的心里一直是一颗种子&#xff0c;2024年初&#xff0c;当时的想法是考研和就业两手抓。买了张宇的高数现代&#xff0c;想要死磕&#xff01; 也记了挺多笔记... 如果…

【实践案例】使用Dify构建文章生成工作流【在线搜索+封面图片生成+内容标题生成】

文章目录 概述开始节点图片封面生成关键词实时搜索主题参考生成文章详情和生成文章标题测试完整工作流运行测试结果 概述 使用Dify构建文章生成工作流&#xff0c;使用工具包括&#xff1a;使用 Tavily 执行的搜索查询&#xff0c;使用Flux生成封面图片&#xff0c;使用Stable…

Linux线程安全

文章目录 &#x1f96d;Linux线程互斥进程线程间的互斥相关背景概念互斥锁mutex互斥锁的接口互斥锁实现原理探究 &#x1f34d;可重入VS线程安全概念常见的线程不安全的情况常见的线程安全的情况常见的不可重入的情况常见的可重入的情况可重入与线程安全联系可重入与线程安全区…

csapp2.4节——浮点数

目录 二进制小数 十进制小数转二进制小数 IEEE浮点表示 规格化表示 非规格化表示 特殊值 舍入 浮点运算 二进制小数 类比十进制中的小数&#xff0c;可定义出二进制小数 例如1010.0101 小数点后的权重从-1开始递减。 十进制小数转二进制小数 整数部分使用辗转相除…

在php中怎么打开OpenSSL

&#xff08;点击即可进入聊天助手&#xff09; 背景 在使用php做一些项目时,有用到用户邮箱注册等,需要开启openssl的能力 在php系统中openssl默认是关闭状态的,在一些低版本php系统中,有的甚至需要在服务器终端后台,手动安装 要打开OpenSSL扩展&#xff0c;需要进行以下步骤 …

Rust语言进阶之zip用法实例(九十五)

简介&#xff1a; CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布&#xff1a;《Android系统多媒体进阶实战》&#x1f680; 优质专栏&#xff1a; Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a; 多媒体系统工程师系列【…

[权限提升] Windows 提权 — 系统内核溢出漏洞提权

关注这个框架的其他相关笔记&#xff1a;[内网安全] 内网渗透 - 学习手册-CSDN博客 0x01&#xff1a;系统内核溢出漏洞提权介绍 注意&#xff1a;提权很容易让电脑蓝屏&#xff0c;所以如果是测试的话&#xff0c;提权前最好做好系统备份。 溢出漏洞就像是往杯子里装水 —— 如…

Windows11 安装poetry

使用powershell安装 (Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | py - 如果使用py运行失败则替换为python即可 终端运行结果如下 D:\AI\A_Share_investment_Agent> (Invoke-WebRequest -Uri https://install.python-poetry.…

系统思考—心智模式

“我们的大脑对连贯性的渴望远胜于对准确性的追求。”—诺贝尔经济学得主丹尼尔卡尼曼 在面对复杂的决策时&#xff0c;我们往往更倾向于寻找那些能够迅速串联起来的信息&#xff0c;而非深入挖掘每一个细节的真实性。这种倾向在日常生活中或许能帮助我们迅速作出决策&#xf…

基于ollama,langchain,springboot从零搭建知识库三【解析文档并存储到向量数据库】

安装环境 安装pgvector&#xff0c;先设置docker镜像源&#xff1a; vim /etc/docker/daemon.json {"registry-mirrors": ["https://05f073ad3c0010ea0f4bc00b7105ec20.mirror.swr.myhuaweicloud.com","https://mirror.ccs.tencentyun.com",&…

Mac m1,m2,m3芯片使用nvm安装node14报错

使用nvm安装了node 12/16/18都没有问题&#xff0c;到14就报错了。第一次看到这个报错有点懵&#xff0c;查询资料发现是Mac芯片的问题。 Issue上提供了两个方案&#xff1a; 1、为了在arm64的Mac上安装node 14&#xff0c;需要使用Rosseta&#xff0c;可以通过以下命令安装 …

学习数据结构(2)空间复杂度+顺序表

1.空间复杂度 &#xff08;1&#xff09;概念 空间复杂度也是一个数学表达式&#xff0c;表示一个算法在运行过程中根据算法的需要额外临时开辟的空间。 空间复杂度不是指程序占用了多少bytes的空间&#xff0c;因为常规情况每个对象大小差异不会很大&#xff0c;所以空间复杂…