C++的数据结构(五):树和存储结构及示例

        在计算机科学中,树是一种抽象数据类型(ADT)或是实现这种抽象数据类型的数据结构,用来模拟具有树状结构性质的数据集合。这种数据结构以一系列连接的节点来形成树形结构。在C++中,树的概念和存储结构是实现各种复杂算法和数据操作的基础。   

     树是由节点和边组成的图,其中每个节点有零个或多个子节点,但只有一个父节点(除了根节点,它没有父节点)。树的顶部节点称为根节点。如果一个节点没有子节点,那么它被称为叶子节点。除了根节点和叶子节点之外的其他节点称为内部节点。由树的根节点和若干棵子树所构成的树称为森林。如下图所示。

         树的术语:    

        (1)路径:在两个节点之间,一系列的边和节点的组合。路径的长度是组成路径的边数。

        (2)深度:一个节点的深度是指从根节点到该节点的最长路径上的边数。根节点的深度为0。

        (3)层次:树的层次从根开始定义,根为第一层,根的子节点为第二层,以此类推。

        (4)高度:树的高度是从叶子节点开始自底向上逐层累加的路径上边的数量。根节点的高度就是树的高度。

        在C++中,树的存储结构主要有两种:顺序存储和链式存储。不同的存储结构对应着不同的表示方法,如孩子表示法、双亲表示法、孩子兄弟表示法等。

        1. 顺序存储:顺序存储通常用于完全二叉树。在完全二叉树中,除了最后一层外,其他层的节点数是满的,并且最后一层的节点都靠左排列。这种特性使得完全二叉树可以使用数组进行顺序存储,其中每个节点的索引与其在树中的位置相关。

        示例:创建一棵简单的完全二叉树,代码如下。

#include <iostream>
#include <vector>using namespace std;class TreeNode {
public:int value;TreeNode* left;TreeNode* right;TreeNode(int x) : value(x), left(nullptr), right(nullptr) {}
};class BinaryTree {
private:vector<TreeNode*> nodes;
public:// 初始化树的根节点void initRoot(int value) {nodes.push_back(new TreeNode(value));}// 添加子节点void addChild(int parentIndex, int leftChildValue, int rightChildValue) {int nextEmptyIndex = nodes.size();if (leftChildValue != -1) {nodes.push_back(new TreeNode(leftChildValue));nodes[parentIndex]->left = nodes[nextEmptyIndex];}if (rightChildValue != -1) {nodes.push_back(new TreeNode(rightChildValue));nodes[parentIndex]->right = nodes[nextEmptyIndex + (leftChildValue != -1)];}}// 示例:创建一棵简单的完全二叉树void createExampleTree() {initRoot(1);addChild(0, 2, 3);addChild(1, 4, 5);addChild(2, 6, -1);addChild(3, 7, 8);}// 其他操作,如遍历、查找等...
};

        链式存储:链式存储通过节点和指针来表示树中的关系。每个节点包含数据域和指向其子节点的指针域。链式存储方式更加灵活,适用于各种类型的树。

        示例一:使用孩子表示法创建树,代码如下。

class TreeNode {
public:int value;vector<TreeNode*> children;TreeNode(int x) : value(x) {}
};// 使用孩子表示法创建树
TreeNode* createTree() {TreeNode* root = new TreeNode(1);TreeNode* node2 = new TreeNode(2);TreeNode* node3 = new TreeNode(3);TreeNode* node4 = new TreeNode(4);TreeNode* node5 = new TreeNode(5);root->children.push_back(node2);root->children.push_back(node3);node2->children.push_back(node4);node2->children.push_back(node5);return root;
}

        上述代码展示了如何使用孩子表示法来创建一个树,其中每个节点都有一个指向其子节点的指针列表。这种方式可以很直观地表示一个节点的所有子节点,但是在查找父节点时不够高效,因为父节点的信息并未存储在当前节点中。

        在双亲表示法中,每个节点不仅包含数据域和指向其子节点的指针,还包含一个指向其父节点的指针。这使得我们可以方便地访问一个节点的父节点,但可能需要额外的空间来存储父节点的指针。

        示例二:使用双亲表示法创建树,代码如下:

class TreeNode {
public:int value;TreeNode* parent; // 指向父节点的指针vector<TreeNode*> children; // 子节点列表TreeNode(int x) : value(x), parent(nullptr) {}
};// 使用双亲表示法创建树
void createTreeWithParent(TreeNode*& root) {root = new TreeNode(1); // 根节点的父节点为nullTreeNode* node2 = new TreeNode(2);TreeNode* node3 = new TreeNode(3);TreeNode* node4 = new TreeNode(4);TreeNode* node5 = new TreeNode(5);node2->parent = root;node3->parent = root;node4->parent = node2;node5->parent = node2;root->children.push_back(node2);root->children.push_back(node3);node2->children.push_back(node4);node2->children.push_back(node5);
}

        在双亲表示法中,我们可以沿着父节点的指针向上遍历树,直到找到根节点或者到达一个父节点为空的节点。这种表示法在需要频繁进行父子节点关系查询时比较有用。

        孩子兄弟表示法是一种结合了孩子表示法和双亲表示法的思想的方法。在这种表示法中,每个节点包含指向其第一个孩子节点的指针和指向其下一个兄弟节点的指针。这种表示法对于二叉树非常自然,并且可以很方便地表示任何类型的树。
        示例三: 使用孩子兄弟表示法创建树,代码如下:

class TreeNode {
public:int value;TreeNode* firstChild; // 指向第一个孩子节点TreeNode* nextSibling; // 指向下一个兄弟节点TreeNode(int x) : value(x), firstChild(nullptr), nextSibling(nullptr) {}
};// 使用孩子兄弟表示法创建树
void createTreeWithChildSibling(TreeNode*& root) {root = new TreeNode(1);TreeNode* node2 = new TreeNode(2);TreeNode* node3 = new TreeNode(3);TreeNode* node4 = new TreeNode(4);TreeNode* node5 = new TreeNode(5);root->firstChild = node2;node2->nextSibling = node3;node3->firstChild = node4;node3->nextSibling = node5;
}

        在这种表示法中,通过firstChild可以访问到该节点的所有子节点,而通过nextSibling可以遍历该节点的所有兄弟节点。这种方法特别适合处理那些子节点之间没有顺序要求的树结构。

        每种存储结构都有其适用的场景和优缺点,例如顺序存储适合表示完全二叉树,而链式存储则更加灵活,能够表示任意结构的树。在实际应用中,需要根据具体需求和树的特点来选择适当的存储结构。

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

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

相关文章

Java--初识类和对象

前言 本篇讲解Java类和对象的入门版本。 学习目的&#xff1a; 1.理解什么是类和对象。 2.引入面向对象程序设计的概念 3.学会如何定义类和创建对象。 4.理解this引用。 5.了解构造方法的概念并学会使用 考虑到篇幅过长问题&#xff0c;作者决定分多次发布。 面向对象的引入 J…

GIAT: 蛋白质结构预测的新利器

瑞典Karolinska研究院在瑞典政府赞助下由Ben Murrell等研究团队在AlphaFold 3最新报告后提出这篇论文提出了一种非常有趣和创新的方法来生成蛋白质骨架结构,称为生成式不变角度转换器(GIAT)。与现有的主要基于扩散模型和流匹配的方法不同,GIAT采用了类似于大型语言模型(如GPT)中…

【C语言|数据结构】双向链表

文章目录 前言1、初步认识双向链表1.1 定义&#xff1a;1.2 结构1.3 节点的存储 2、双向链表的接口函数2.1 链表的节点的动态申请2.2 链表的初始化2.3 尾插2.4 头插2.5 头删2.5 尾删2.6 在pos节点后面添加数据2.6 删除pos节点 3、双向链表的实现&#xff1a; 前言 各位小伙伴大…

C控制语句:分支和跳转

1.1if语句 //colddays.c --找出0摄氏度以下的天数占总天数的百分比 #include <stdio.h>int main(void) {const int FREEZING 0;float temperature;int cold_days 0;int all_days 0;printf("Enter the list of daily low temperature.\n");printf("Use…

电子学会C/C++编程等级考试2024年03月(八级)真题解析

C/C编程&#xff08;1~8级&#xff09;全部真题・点这里 第1题&#xff1a;道路 N个以 1 … N 标号的城市通过单向的道路相连:。每条道路包含两个参数&#xff1a;道路的长度和需要为该路付的通行费&#xff08;以金币的数目来表示&#xff09; Bob and Alice 过去住在城市 1.在…

蓝海创业商机小吃配方项目,日入200+ ,小白可上手,图文创作转现快

小吃技术销售&#xff0c;一单价格从几元到几百元不等&#xff0c;行业竞争相对较小&#xff0c;是一个相对冷门的领域。只需一部手机&#xff0c;就可以发布图文并茂的内容&#xff0c;配上背景音乐&#xff08;BGM&#xff09;&#xff0c;即使是对视频剪辑不熟悉的新手&…

面试中算法(金矿)

有一位国王拥有5座金矿&#xff0c;每座金矿的黄金储量不同&#xff0c;需要参与挖掘的工人人数也不同。 例如&#xff0c;有的金矿储量是5ookg黄金&#xff0c;需要5个工人来挖掘;有的金矿储量是2ookg黄金&#xff0c;需要3个工人来挖掘...... 如果参与挖矿的工人的总数是10。…

试衣不再有界:Tunnel Try-on开启视频试衣应用新纪元

论文&#xff1a;https://arxiv.org/pdf/2404.17571 主页&#xff1a;https://mengtingchen.github.io/tunnel-try-on-page/ 一、摘要总结 随着虚拟试衣技术的发展&#xff0c;消费者和时尚行业对于能够在视频中实现高质量虚拟试衣的需求日益增长。这项技术允许用户在不实际穿…

目标检测——印度车辆数据集

引言 亲爱的读者们&#xff0c;您是否在寻找某个特定的数据集&#xff0c;用于研究或项目实践&#xff1f;欢迎您在评论区留言&#xff0c;或者通过公众号私信告诉我&#xff0c;您想要的数据集的类型主题。小编会竭尽全力为您寻找&#xff0c;并在找到后第一时间与您分享。 …

区块链中的APP与传统APP的区别

一、技术 区块链中的APP是基于区块链技术开发的&#xff0c;而传统APP则基于传统的应用程序商店或网页。区块链中的APP利用区块链技术的去中心化、数据不可篡改等特点&#xff0c;使得应用程序的开发和分发更加安全、透明和可信。与传统APP相比&#xff0c;区块链中的APP无需中…

Web安全:SQL注入之布尔盲注原理+步骤+实战操作

「作者简介」&#xff1a;2022年北京冬奥会网络安全中国代表队&#xff0c;CSDN Top100&#xff0c;就职奇安信多年&#xff0c;以实战工作为基础对安全知识体系进行总结与归纳&#xff0c;著作适用于快速入门的 《网络安全自学教程》&#xff0c;内容涵盖系统安全、信息收集等…

访客管理系统对于校园安全的重要性

校园访客办理计划是针对校园安全需求规划的安全办理体系&#xff0c;主要用于对校园外来人员的科学办理。要做好校园安全作业&#xff0c;把风险分子拒之门外尤为要害。校园访客办理计划实现访客实名制&#xff0c;并结合公安网、黑名单功用&#xff0c;对风险人员进行提前预警…

没有公网ip,如何实现外网访问内网?

目前拨号上网是最广泛的上网方式&#xff0c;这种方式优点是价格便宜&#xff0c;缺点是没有固定公网ip&#xff0c;每次重新您拨号ip地址都会变。如果有一台服务器&#xff0c;需要实现外网访问&#xff0c;在没有固定公网ip的环境下&#xff0c;该如何实现呢&#xff1f;使用…

【CTF Web】QSNCTF 文章管理系统 Writeup(SQL注入+Linux命令+RCE)

文章管理系统 题目描述 这是我们的文章管理系统&#xff0c;快来看看有什么漏洞可以拿到FLAG吧&#xff1f;注意&#xff1a;可能有个假FLAG哦 解法 SQL 注入。 ?id1 or 11 --取得假 flag。 爆库名。 ?id1 union select 1,group_concat(schema_name) from information_sch…

华为OD机试【统一限载货物数最小值】(java)(200分)

1、题目描述 火车站附近的货物中转站负责将到站货物运往仓库&#xff0c;小明在中转站负责调度 2K 辆中转车(K辆干货中转车&#xff0c;K 辆湿货中转车)货物由不同供货商从各地发来&#xff0c;各地的货物是依次进站&#xff0c;然后小明按照卸货顺序依次装货到中转车&#xf…

二维数组 和 变长数组

在上一期的内容中&#xff0c;为诸君讲解到了一维数组&#xff0c;在一维数组的基础上&#xff0c;C语言中还有着多维数组&#xff0c;其中&#xff0c;比较典型且运用较为广泛的就是我们今天的主角——二维数组 一 . 二维数组的概念 我们把单个或者多个元素组成的数组定义为一…

VScode 修改 Markdown Preview Enhanced 主题与字体

VScode 修改 Markdown Preview Enhanced 主题与字体 1. 修改前后效果对比2. 修改主题2.1 更改默认主题2.2 修改背景色 3. 修改字体 VS Code基础入门使用可查看&#xff1a; VS Code 基础入门使用&#xff08;配置&#xff09;教程 其他Vs Code 配置可关注查看&#xff1a; Vs C…

2024年如何选什么版本FL Studio才适合自己编曲?

fl studio是什么软件 水果编曲软件 FL Studio&#xff0c;全称为Fruity Loops Studio&#xff0c;是一款全能音乐制作环境或数字音频工作站&#xff08;DAW&#xff09;&#xff0c;集编曲、录音、剪辑、混音等多种功能于一身。 FL Studio最初名为Fruity Loops&#xff0c;因…

外网如何访问内网?快解析

由于公网IP资源短缺&#xff0c;我们的电脑大多处于内网环境&#xff0c;如何在外网访问内网电脑&#xff0c;成为一个令人头疼的问题&#xff0c;下面我给大家推荐一个非常实用的方法。 1&#xff1a;访问快解析下载安装快解析服务器 2&#xff1a;运行软件&#xff0c;点击“…

2.4 输入和显示

本节必须掌握的知识点&#xff1a; 示例五源代码 代码分析 汇编解析 2.4.1 示例五 ■格式化输入函数scanf scanf函数可以从键盘读取输入的信息。scanf函数同样可以像printf函数那样&#xff0c;通过转换说明“%d”来限制函数只能读取十进制数。scanf函数的参数为可变参数…