【C语言数据结构(基础版)】第五站:树和二叉树(上)

简介: 【C语言数据结构(基础版)】第五站:树和二叉树

一、树的概念及结构

1.树的概念

树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成的一个具有层次关系的集合。把它叫做树是因为它看起来像一颗倒挂的树,也就是说它是根朝上,而叶朝下的。

①有一个特殊的结点,称为根结点,根结点没有前驱结点

②除根结点外,其余结点被分成M(M>0)个互不相交的集合T1、T2、......、Tm。其中每一个集合Ti(1<=i<=m)又是一颗与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或者多个后继。

③因此,树是递归定义的

如下图所示是一张树的图片

除此之外我们还有很多树的概念需要了解,我们就利用下图来了解一下树的概念

节点的度 一个节点含有的子树的个数称为该节点的度;如上图中的:A的度为6
叶节点或终端节点 度为0的节点称为叶节点;如上图B、C、H、I...等节点都为叶节点
非终端节点或分支节点 度不为0的节点;如上图:D、E、F、G...等节点为分支节点
双亲节点或父节点 若一个节点含有子节点,则这个节点称为其子节点的父节点;如上图:A是B的父节点
孩子节点或子节点 一个节点含有的子树的根节点称为该节点的子节点;如上图:B是A的子节点
兄弟节点 具有相同父节点的节点互称兄弟节点;如上图:B、C是兄弟节点
树的度 一棵树中,最大节点的度称为树的度;如上图:树的度是6
节点的层次 从根开始定义起,根为第一层,根的子节点为第二层,以此类推
树的高度或深度 树中节点的最大层次;如上图:树的高度为4
节点的祖先

从根到该节点所经分支上的所有节点;如上图:A是所有节点的祖先

子孙 以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是A的子孙
森林 由m棵互不相交的多颗树的集合称为森林;

了解了这些概念的话,那么我们肯定就知道了如何看待这样一棵树,下面是一颗普通的树,这些树我们都可有看作是根和多颗子树组成的

当然还有一些长得比较像树,但他其实不是树,如下图中三棵都不是树

因为树需要满足:

1.子树是不相交的

2.除了根节点外,每个结点有且仅有一个父节点

3.一颗N个结点的树有N-1条边

2.树的表示

我们知道,像这种树的定义就是一件比较头疼的事情,比如我们一个节点里面该定义几个指针,我们根本不知道,除非它说了树的度为6。那这样我们就可有定义六个指针,但是这样浪费又很大。如果大部分的地方只有一个子树,那么这个节点的浪费就很大了。

所以有的人就想出了这样一种方式,在c++中,有的人使用顺序表来存储这个指针,不规定一开始又多少个子树,而是采用动态增容的方式来实现的

当然还有另外一种比较巧的方式

也就是左孩子右兄弟表示法,这又是什么表示法呢?我们先写出它的节点定义,如下图所示,它永远都是两个指针,一个只指向最左边的孩子,另外一个指向它的兄弟节点,这样的话,如果还有右边的兄弟的话,那就是让兄弟节点继续指向下一个兄弟。直到为空。然后孩子节点指向它这个节点的孩子节点,同样也是分为左孩子和右兄弟

具体他们的指向图如下

还有一种方式是双亲表示法,如下图所示

我们将每一个节点都给他一个下标,放到一个数组里面,比如R是0,A是1等,我们让这些不指向他们的孩子,而是让孩子指向父亲

然后R因为它是根了,所以它里面是-1。而像ABCD之类的节点就让他们与他们的双亲结点的下标相联系起来。这样我们也可以表示出整个树

3.树在实际中的应用

我们这里举一个简单的例子,比如我们的文件夹就是一个树

二、二叉树概念及结构

1.概念

一颗二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根结点加上两颗分别称为左子树和右子树的二叉树组成

二叉树的特点

1.每个结点最多有两个子树,即二叉树不存在度大于2的结点

2.二叉树的子树有左右之分,其子树的次序不能颠倒

如下图所示就是一个二叉树

2.特殊的二叉树

1.满二叉树:

一个二叉树,如果每一层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果二叉树的层数为k,它的结点总数为2^k-1,那么这是一个满二叉树

如下图所示就是一个满二叉树

看着图我们也能理解这个满二叉树了,而它的层数为k的话,它的第一层是2^0个结点,第二层是2^1个结点,第三层是2^2个结点.......第k层是2^(k-1)个结点,那么对其求和之后它的总结点数当然就是2^k-1个结点了。同样的我们也可以解出来有N个结点的满二叉树层数为log(N+1),这里的对数是以2为底的。

2.完全二叉树:

完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为k的,有n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中编号从1至n的结点一一一对应时称之为完全二叉树。要注意的是满二叉树是一种特殊的完全二叉树

需要特别注意的是,完全二叉树的最后一层如果是不满的话,那么最后一层结点必须是按顺序的,从左到右两个子树中不能出现空树,否则不是完全二叉树。

也就是说假设树的高度是h

1.前h-1层都是满的

2.最后一层不满,但是最后一层从左到右都是连续的

完全二叉树的结点个数我们也很容易的得到是2^k-1-x,x为完全二叉树对应的满二叉树所缺的元素个数。

所以如果知道结点的个数N,我们也可以反推出高度为log(N+1+X),其中该对数是以2为底数的。而且这个高度我们可以近似认为是logN,以2为底数。因为X是小于等于N二大于等于0的。我们只需要近似的算出高度,向上取整即可

3.二叉树的性质

1.若规定根节点的层数为1,则一颗非空二叉树的第i层上最多有2^(i-1)个结点。

2.若规定根节点的层数为1,则深度为h的二叉树最大的结点数是2^h-1

3.对于任何一颗二叉树,如果度为0的叶结点个数为n0,度为2的分支结点个数为n2,则有n0=n2+1

4.若规定根结点的层数为1,具有N个结点的满二叉树的深度为logN

这里是一些二叉树的一些选择题

1. 某二叉树共有 399 个结点,其中有 199 个度为 2 的结点,则该二叉树中的叶子结点数为( )

A 不存在这样的二叉树         B 200        C 198        D 199

对于这道题,其实如果不知道性质3的话是很难想出来的,由性质三的,度为0的结点个数是度为2的结点个数+1直接得到答案是200

也就是说这道题跟这个399没有关系

2.在具有 2n 个结点的完全二叉树中,叶子结点个数为( )

A n         B n+1         C n-1         D n/2

对于这道题,我们可能一开始也是很懵的。但是其实还是考察二叉树的性质

设度为0的结点个数为x0,度为1的结点个数为x1,度为2的结点个数为x2

所以我们就知道了,x0+x1+x2=2n        //这是题目给出的第一个方程

然后由性质三得到x0=x2+1        //第二个方程

其实到了这里,我们看似没有条件,但是题目中说了是完全二叉树,所以它的度为1的结点个数要么是0要么是1。所以我们无非就是将两种情况都算一遍就可以了

最终解出来的答案只有A符合

3.一棵完全二叉树的节点数位为531个,那么这棵树的高度为( )

A 11         B 10         C 8        D 12

对于这道题,也是考察二叉树的性质,按照我们的公式就是直接logN,然后最终结果向上取整即可

我们知道1024是2的十次方,512是2的9次方,而它刚好落在这个范围内,所以最终的计算结果应该是9.xxxxx,而它向上取整刚好就是10,所以高度为10

4.二叉树的存储结构

二叉树一般可以使用两种结构存储:一种顺序结构,另外一种链式结构

(1)顺序存储

顺序结构存储就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费。而现实中只有堆才会使用数组来存储。二叉树顺序存储在物理上是一个数组,在逻辑上是一颗二叉树

(2)链式存储

二叉树的链式存储结构是指,用链表表示一颗二叉树,即用链来指示元素的逻辑关系。通常的方法是链表中每个结点由三个域组成。数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在链结点的存储地址。链式结构又分为二叉链,三叉链。我们现在所用的都是二叉链

下面是二叉链与三叉链的声明

三、二叉树链式结构的实现

1.二叉树的前序中序后序(深度优先遍历)

(1)树的分割

我们得先将一颗树的结构给理清楚,一棵树由三部分构成,分别是根节点,左子树,右子树。

比如说下面这棵树

我们是这样看这棵树的

这棵树首先分为根节点A,左子树B,右子树C

然后我们继续具体细分,左子树B中,又可分为根节点B,左子树D,右子树E。而右子树C中,又可分为根节点C,左子树空树,右子树空树

然后继续具体细分,D这棵树可分为根节点D和左子树空,右子树空,E这颗树可分为根节点C,左子树空,右子树空

这就是我们看待一颗树时候的看法

这也是分治算法:分而治之,大问题分为类似的子问题,子问题在分为子问题...直到子问题不可再分割

相关文章
|
存储 算法 Java
算法系列之数据结构-二叉树
树是一种重要的非线性数据结构,广泛应用于各种算法和应用中。本文介绍了树的基本概念、常见类型(如二叉树、满二叉树、完全二叉树、平衡二叉树、B树等)及其在Java中的实现。通过递归方法实现了二叉树的前序、中序、后序和层次遍历,并展示了具体的代码示例和运行结果。掌握树结构有助于提高编程能力,优化算法设计。
402 10
 算法系列之数据结构-二叉树
|
算法 Java
算法系列之数据结构-Huffman树
Huffman树(哈夫曼树)又称最优二叉树,是一种带权路径长度最短的二叉树,常用于信息传输、数据压缩等方面。它的构造基于字符出现的频率,通过将频率较低的字符组合在一起,最终形成一棵树。在Huffman树中,每个叶节点代表一个字符,而每个字符的编码则是从根节点到叶节点的路径所对应的二进制序列。
387 3
 算法系列之数据结构-Huffman树
|
存储 自然语言处理 数据库
【数据结构进阶】AVL树深度剖析 + 实现(附源码)
在深入探讨了AVL树的原理和实现后,我们不难发现,这种数据结构不仅优雅地解决了传统二叉搜索树可能面临的性能退化问题,还通过其独特的平衡机制,确保了在任何情况下都能提供稳定且高效的查找、插入和删除操作。
871 19
|
存储 C++
【C++数据结构——树】哈夫曼树(头歌实践教学平台习题) 【合集】
【数据结构——树】哈夫曼树(头歌实践教学平台习题)【合集】目录 任务描述 相关知识 测试说明 我的通关代码: 测试结果:任务描述 本关任务:编写一个程序构建哈夫曼树和生成哈夫曼编码。 相关知识 为了完成本关任务,你需要掌握: 1.如何构建哈夫曼树, 2.如何生成哈夫曼编码。 测试说明 平台会对你编写的代码进行测试: 测试输入: 1192677541518462450242195190181174157138124123 (用户分别输入所列单词的频度) 预
536 14
【C++数据结构——树】哈夫曼树(头歌实践教学平台习题) 【合集】
|
定位技术 C语言
c语言及数据结构实现简单贪吃蛇小游戏
c语言及数据结构实现简单贪吃蛇小游戏
|
搜索推荐 C语言
数据结构(C语言)之对归并排序的介绍与理解
归并排序是一种基于分治策略的排序算法,通过递归将数组不断分割为子数组,直到每个子数组仅剩一个元素,再逐步合并这些有序的子数组以得到最终的有序数组。递归版本中,每次分割区间为[left, mid]和[mid+1, right],确保每两个区间内数据有序后进行合并。非递归版本则通过逐步增加gap值(初始为1),先对单个元素排序,再逐步扩大到更大的区间进行合并,直至整个数组有序。归并排序的时间复杂度为O(n*logn),空间复杂度为O(n),且具有稳定性,适用于普通排序及大文件排序场景。
|
Java C++
【C++数据结构——树】二叉树的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现二叉树的基本运算。​ 相关知识 创建二叉树 销毁二叉树 查找结点 求二叉树的高度 输出二叉树 //二叉树节点结构体定义 structTreeNode{ intval; TreeNode*left; TreeNode*right; TreeNode(intx):val(x),left(NULL),right(NULL){} }; 创建二叉树 //创建二叉树函数(简单示例,手动构建) TreeNode*create
462 12
|
C++
【C++数据结构——树】二叉树的性质(头歌实践教学平台习题)【合集】
本文档介绍了如何根据二叉树的括号表示串创建二叉树,并计算其结点个数、叶子结点个数、某结点的层次和二叉树的宽度。主要内容包括: 1. **定义二叉树节点结构体**:定义了包含节点值、左子节点指针和右子节点指针的结构体。 2. **实现构建二叉树的函数**:通过解析括号表示串,递归地构建二叉树的各个节点及其子树。 3. **使用示例**:展示了如何调用 `buildTree` 函数构建二叉树并进行简单验证。 4. **计算二叉树属性**: - 计算二叉树节点个数。 - 计算二叉树叶子节点个数。 - 计算某节点的层次。 - 计算二叉树的宽度。 最后,提供了测试说明及通关代
247 10
|
存储 缓存 C语言
数据结构——双链表(C语言)
数据结构——双链表(C语言)
|
存储 C语言
【数据结构】手把手教你单链表(c语言)(附源码)
本文介绍了单链表的基本概念、结构定义及其实现方法。单链表是一种内存地址不连续但逻辑顺序连续的数据结构,每个节点包含数据域和指针域。文章详细讲解了单链表的常见操作,如头插、尾插、头删、尾删、查找、指定位置插入和删除等,并提供了完整的C语言代码示例。通过学习单链表,可以更好地理解数据结构的底层逻辑,提高编程能力。
1482 4