Linux最新从零开始学数据结构与算法(四) :二叉树 (二叉树的性质,遍历,2024年最新并发知识体系大全

最后的话

最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家!

资料预览

给大家整理的视频资料:

给大家整理的电子书资料:

如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以点击这里获取!

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

在上述示例中,节点数据列显示了每个节点存储的数据。子节点指针列显示了每个节点的子节点的位置信息。例如,节点A的子节点是节点B和节点C。

使用孩子表示法,可以轻松地遍历树结构,从根节点开始,通过子节点指针访问每个节点的子节点。然而,需要注意的是,孩子表示法可能需要处理节点的变长子节点指针,或者使用额外的数据结构(如数组)来存储子节点指针,以便有效地表示树结构。

下面给出孩子表示法的存储结构定义:

#define MaxSize 100
typedef char DataType;
typedef struct ChildNode
{
	int child;
	struct ChildNode \* next;
} ChildNode;

typedef struct
{
	DataType data;
	ChildNode \* first;
} TreeNode;

typedef struct
{
	TreeNode tree[Maxsize];
	int treeNum; //定义孩子表示法存储结构
} CTree;

3.孩子兄弟表示法

孩子兄弟表示法(Child-Sibling Representation),也称为二叉树表示法或二叉链表表示法,是一种用于表示树结构的方法,它利用节点的孩子指针和兄弟指针来表示节点之间的关系。

在孩子兄弟表示法中,每个节点包含三个信息:

  1. 数据:节点所存储的值或数据。
  2. 第一个孩子指针(First Child Pointer):指向该节点的第一个孩子节点。
  3. 下一个兄弟指针(Next Sibling Pointer):指向该节点的下一个兄弟节点。

使用孩子兄弟表示法,可以用二叉树的结构来表示一般的树结构。每个节点的第一个孩子指针指向其第一个子节点,而下一个兄弟指针指向其下一个兄弟节点。

以下是一个示例,展示了一个使用孩子兄弟表示法表示的树结构:

节点数据:    A   B   C   D   E   F   G   H   I   J
第一个孩子指针: B   -   D   -   G   -   -   -   -   -
下一个兄弟指针: C   -   E   F   -   -   -   -   -   -

在上述示例中,节点数据列显示了每个节点存储的数据。第一个孩子指针列显示了每个节点的第一个孩子节点的位置信息。下一个兄弟指针列显示了每个节点的下一个兄弟节点的位置信息。

使用孩子兄弟表示法,可以轻松地遍历树结构,从根节点开始,通过第一个孩子指针和下一个兄弟指针访问每个节点的子节点和兄弟节点。这种表示方法节省了存储空间,并且在某些操作(如树的遍历和查找)上具有较好的性能。

孩子兄弟表示法常用于表示二叉树和森林(由多个不相交的树组成),尤其适用于树的动态操作和算法实现。

需要注意的是,孩子兄弟表示法在进行插入和删除操作时可能需要调整节点的指针,以维持正确的关系,并确保树的结构仍然有效。

孩子兄弟表示法是树结构的一种常用表示方法,但根据具体的应用需求和操作需求,选择适合的树表示方法是很重要的。

下面给出孩子兄弟表示法的存储结构定义:

typedef char DataType;
typedef struct CSNode
{
	DataType data;
	struct CSNode \* firstchild, \* rightsib;
} CSNode;
CsNode \*root; // 定义根指针

三、二叉树的逻辑结构

1.二叉树的定义

1.1 二叉树

二叉树(Binary Tree)是一种特殊的树结构,其中每个节点最多有两个子节点,分别称为左子节点和右子节点。

二叉树的定义如下:

  1. 空树(Empty Tree):一个没有节点的二叉树被称为空树。
  2. 根节点(Root Node):二叉树中的一个特殊节点被称为根节点,它是二叉树的顶部节点,没有父节点与之相连。
  3. 节点(Node):二叉树中的每个节点包含一个值或数据,并且可以连接到最多两个子节点。每个节点可以有零个、一个或两个子节点。
  4. 左子节点(Left Child Node):一个节点连接到它的左侧子节点的节点被称为左子节点。
  5. 右子节点(Right Child Node):一个节点连接到它的右侧子节点的节点被称为右子节点。
  6. 叶节点(Leaf Node):叶节点是没有子节点的节点,它们位于二叉树的末端。

需要注意的是,二叉树中的节点可以有一个子节点为空(缺失),但不能有两个子节点都为空的情况。

二叉树的特点是每个节点最多有两个子节点,其中左子节点和右子节点的顺序是有意义的,不可以随意的颠倒。二叉树的结构可用于模拟层次关系、排序和搜索等应用。

1.2 斜树

斜树(Skewed Tree)是一种特殊类型的二叉树,它的所有节点都只有一个子节点,要么都是左子节点,要么都是右子节点。

根据子节点的位置,斜树可以分为两种类型:

  1. 左斜树(Left Skewed Tree):所有节点都只有左子节点,没有右子节点。每个节点的右子节点为空。
        1
       /
      2
     /
    3
   /
  4

  1. 右斜树(Right Skewed Tree):所有节点都只有右子节点,没有左子节点。每个节点的左子节点为空。
  1
   \
    2
     \
      3
       \
        4

**斜树是二叉树的一种特殊情况,因为它的所有节点只有一个子节点,所以斜树的高度等于节点的数量。**斜树的形状类似于一个单向链表,只有一个方向上的连接。

斜树在某些特定场景下可能会出现,但在一般情况下并不常见。它的特殊性使得斜树的插入和删除操作相对简单,但访问和搜索效率较低,因为树的平衡性被破坏了。

需要注意的是,斜树是二叉树的一种特殊情况,与其他类型的二叉树(如平衡二叉树、完全二叉树等)相比,斜树的应用范围较为有限。在大多数情况下,我们更倾向于使用平衡性更好的二叉树结构。

1.3 满二叉树

满二叉树(Full Binary Tree)是一种特殊类型的二叉树,其中除了叶节点外,每个节点都有两个子节点,并且所有叶节点都在同一层级上。

满二叉树的定义如下:

  1. 空树(Empty Tree):一个没有节点的二叉树被称为空树。
  2. 根节点(Root Node):二叉树中的一个特殊节点被称为根节点,它是二叉树的顶部节点,没有父节点与之相连。
  3. 节点(Node):二叉树中的每个节点包含一个值或数据,并且可以连接到最多两个子节点。每个节点可以有零个、一个或两个子节点。
  4. 叶节点(Leaf Node):叶节点是没有子节点的节点,它们位于二叉树的末端。
  5. 每个非叶节点都有两个子节点:除了叶节点外,满二叉树的每个非叶节点都有两个子节点。
  6. 所有叶节点在同一层级上:满二叉树的所有叶节点都位于同一层级上,也就是说从根节点到叶节点的路径长度是相同的。

下图是一个示例,展示了一个满二叉树的结构:

         A
       /   \
      B     C
     / \   / \
    D   E F   G

在上述示例中,每个非叶节点都有两个子节点,而且所有叶节点(D、E、F、G)都在同一层级上。

满二叉树具有良好的平衡性和规律性,它的高度(从根节点到最深层的叶节点的路径长度)为log2(n+1),其中n是满二叉树中的节点数量。满二叉树的节点数量为2^h - 1,其中h是满二叉树的高度。

满二叉树在一些算法和数据结构中具有重要的应用,例如堆排序、完全二叉树的表示等。由于其特定的性质,满二叉树的插入和删除操作相对复杂,但在某些场景下,满二叉树能够提供更高效的存储和访问方式。

1.4 完全二叉树

完全二叉树(Complete Binary Tree)是一种特殊类型的二叉树,除了最后一层外,所有层的节点都被填满,且最后一层的节点都尽可能地靠左排列。

完全二叉树的定义如下:

  1. 空树(Empty Tree):一个没有节点的二叉树被称为空树。
  2. 根节点(Root Node):二叉树中的一个特殊节点被称为根节点,它是二叉树的顶部节点,没有父节点与之相连。
  3. 节点(Node):二叉树中的每个节点包含一个值或数据,并且可以连接到最多两个子节点。每个节点可以有零个、一个或两个子节点。
  4. 最后一层节点靠左排列:在最后一层的节点中,从左到右依次排列,不留有空缺。
  5. 最后一层之前的层都是满的:除了最后一层外,所有的层都被填满,每一层的节点数都达到最大。

下图是一个示例,展示了一个完全二叉树的结构:

         A
       /   \
      B     C
     / \   /
    D   E F

在上述示例中,除了最后一层的节点(F)没有右子节点外,其他层的节点都被填满,且最后一层的节点都尽可能地靠左排列。

完全二叉树具有一些特性:由于它的结构相对规整,因此可以使用数组或顺序存储来表示,同时也便于使用索引进行节点的访问和操作。完全二叉树在一些算法和数据结构中具有重要的应用,例如优先队列(使用堆实现)和哈夫曼树等。

需要注意的是,完全二叉树不一定是满二叉树,因为最后一层可以不是满的。而满二叉树的定义是除了叶节点外,每个节点都有两个子节点,并且所有叶节点在同一层级上。

2.二叉树的基本性质

2.1 性质1

**在一棵二叉树中,如果叶子节点的个数为

n

0

n _0

n0​,度为2的结点个数为

n

2

n_2

n2​,则

n

0

=

n

2

1

n_0 = n_2 + 1

n0​=n2​+1。**

2.2 性质2

**二叉树的第 i 层最多有

2

i

1

2^{i - 1}

2i−1个结点(

i

=

1

i >= 1

i>=1)。**

2.3 性质3

**在一棵深度为 k 的二叉树中,最多有

2

k

1

2^k - 1

2k−1 个结点。**

2.4 性质4

**具有 n 个结点的完全二叉树的深度为

log

2

n

1

\left \lfloor \log_{2}{n} \right\rfloor + 1

⌊log2​n⌋+1。**

2.5 性质5

对一棵具有n个结点的完全二叉树从1开始按层序编号,则对于编号为

i

(

1

<

=

i

<

=

n

)

i(1 <= i <= n)

i(1<=i<=n)的结点

i

i

i,有:

**1. 如果

i

1

i > 1

i>1,则结点

i

i

i的父节点编号为

i

/

2

\left \lfloor i/ 2 \right\rfloor

⌊i/2⌋ ;否则结点

i

i

i 是根结点, 无双亲。**
**2. 如果

2

i

<

=

n

2i <= n

2i<=n,则结点的左孩子编号为

2

i

2i

2i ;否则结点无左孩子。**
== **3. 如果

2

i

<

=

n

1

2i <= n + 1

2i<=n+1,则结点的右孩子编号为

2

i

1

2i + 1

2i+1 ;否则结点无右孩子。**

3.二叉树的抽象数据类型定义

和树一样,在不同的情况下,二叉树的基本操作不尽相同。下面给出一些二叉树抽象数据类型定义的例子,包含了部分基本操作:

ADT BiTree
DataModel
	二叉树由一个根节点和两棵互不相交的左右子树构成,二叉树中的结点具有层次关系
Operation
InitBiTree
	输入:无
	功能:初始化一棵二叉树
	输出:一个空的二叉树
CreatBiTree
	输入:n 个结点的数据信息
	功能:建立一棵二叉树
	输出:含有n个结点的二叉树
DestoryBiTree
	输入:无
	功能:销毁一棵二叉树
	输出:释放二叉树所占的内存空间
PreOrder
	输入:无
	功能:前序遍历二叉树
	输出:二叉树的前序遍历序列
InOrder
	输入:无
	功能:中序遍历二叉树
	输出:二叉树的中序遍历序列
PostOrder
	输入:无
	功能:后序遍历二叉树
	输出:二叉树的后序遍历序列
LeverOrder
	输入:无
	功能:层序遍历二叉树
	输出:二叉树的层序遍历序列
endADT

需要注意的是,二叉树的实现方式可以有多种,如链式存储(使用节点对象和引用)或数组存储(使用数组来表示节点及其关系),具体的实现方式可以根据需求和语言特性进行选择。以上定义给出了二叉树的操作接口,在具体实现时可以根据需要进行适当的调整。

4.二叉树的遍历操作

二叉树的遍历是指按照一定的顺序访问二叉树的所有节点。常见的二叉树遍历方式有三种:先序遍历、中序遍历和后序遍历。这些遍历方式可以通过递归或迭代的方式实现。

以下是关于二叉树遍历的一些常见操作:

先序遍历(Preorder Traversal)
先序遍历的顺序是:根节点 -> 左子树 -> 右子树。

递归实现:

  1. 如果树为空,则返回。
  2. 访问当前节点的值。
  3. 递归地对左子树进行先序遍历。
  4. 递归地对右子树进行先序遍历。

迭代实现:

  1. 创建一个空栈,并将根节点压入栈。
  2. 当栈不为空时,执行以下步骤:
    • 弹出栈顶节点,访问该节点的值。
    • 如果存在右子节点,则将右子节点压入栈。
    • 如果存在左子节点,则将左子节点压入栈。

中序遍历(Inorder Traversal)
中序遍历的顺序是:左子树 -> 根节点 -> 右子树。

递归实现:

  1. 如果树为空,则返回。
  2. 递归地对左子树进行中序遍历。
  3. 访问当前节点的值。
  4. 递归地对右子树进行中序遍历。

迭代实现:

  1. 创建一个空栈。
  2. 初始化当前节点为根节点。
  3. 当栈不为空或当前节点不为空时,执行以下步骤:
    • 将当前节点及其所有左子节点依次压入栈,直到当前节点为空。
    • 弹出栈顶节点,访问该节点的值。
    • 将当前节点更新为弹出节点的右子节点。

后序遍历(Postorder Traversal)
后序遍历的顺序是:左子树 -> 右子树 -> 根节点。

递归实现:

  1. 如果树为空,则返回。
  2. 递归地对左子树进行后序遍历。
  3. 递归地对右子树进行后序遍历。
  4. 访问当前节点的值。

迭代实现:

  1. 创建一个空栈。
  2. 初始化当前节点为根节点。
  3. 当栈不为空或当前节点不为空时,执行以下步骤:
    • 将当前节点及其所有左子节点依次压入栈,直到当前节点为空。
    • 如果栈顶节点的右子节点存在且未被访问过,则将当前节点更新为右子节点。
    • 否则,弹出栈顶节点,访问该节点的值,并将当前节点置为空。

层序遍历(Level Order Traversal)
按照层级顺序逐层访问二叉树节点的遍历方式。

层序遍历的步骤如下:

  1. 创建一个空队列(可以使用数组或链表实现)。
  2. 将根节点入队。
  3. 当队列不为空时,执行以下步骤:
    • 弹出队头节点,并访问该节点的值。
    • 如果弹出的节点有左子节点,将左子节点入队。
    • 如果弹出的节点有右子节点,将右子节点入队。

层序遍历会按照从上到下、从左到右的顺序逐层访问二叉树的节点。这意味着在同一层级上,左边的节点会在右边的节点之前被访问到。

下面是一个层序遍历的示例:

         A
       /   \
      B     C
     / \   /
    D   E F

层序遍历的结果为:A, B, C, D, E, F。

在实际实现中,可以使用队列来辅助层序遍历。首先将根节点入队,然后每次从队列中取出一个节点,访问该节点的值,并将其左右子节点(如果存在)依次入队。重复这个过程,直到队列为空,即可完成层序遍历。

层序遍历常用于广度优先搜索(BFS)等算法中,可以用于按层级遍历或搜索树的结构。

四、二叉树的存储结构

1.顺序存储结构

二叉树的顺序存储结构是一种使用数组来表示二叉树的方法。在顺序存储结构中,树的节点按照从上到下、从左到右的顺序依次存储在数组中,通过数组的索引来表示节点之间的关系。

假设二叉树的顺序存储结构使用一个一维数组 arr 来表示,其中根节点存储在索引为 0 的位置,对于任意节点存储在索引 i 的位置上,它的左子节点存储在索引 2i+1 的位置上,右子节点存储在索引 2i+2 的位置上。

下图是一个示例二叉树的顺序存储结构表示:

         A
       /   \
      B     C
     / \   / \
    D   E F   G

对应的顺序存储结构数组为:['A', 'B', 'C', 'D', 'E', 'F', 'G']

在顺序存储结构中,可以通过数组的索引计算出节点之间的关系,例如,索引为 i 的节点的父节点索引为 (i-1)//2,左子节点索引为 2i+1,右子节点索引为 2i+2

顺序存储结构的优点是简单、易于实现和访问,不需要额外的指针和动态内存分配。然而,它对于非完全二叉树会浪费一定的空间,因为可能存在一些数组元素未被使用。

需要注意的是,顺序存储结构适用于静态的二叉树,即在构建树后不会改变其结构。如果需要频繁地进行插入、删除节点操作,顺序存储结构可能不是一个高效的选择,因为需要频繁地调整数组大小和移动元素位置。在这种情况下,链式存储结构(使用节点对象和引用)更为常用和灵活。

下面给出二叉树顺序存储结构的定义:

#define MaxSize 100 //假设二叉树的最大编号
typedef char DataType; //定义二叉树的数据类型,假设为char
typedef struct
{
	DataType data[MaxSize];
	int biTreeNum; //结点个数
} SeqBiTree;

2.二叉链表

2.1 二叉链表的存储结构定义

二叉链表是一种使用节点对象和引用来表示二叉树的存储结构。在二叉链表中,每个节点包含一个数据元素和两个指针,分别指向其左子节点和右子节点(如果存在)。
下面给出二叉链表的存储结构定义:

typedef char DataType;
typedef struct BiNode
{
	DataType data;
	struct BiNode \* lchild, \* rchild;


![](https://img-blog.csdnimg.cn/img_convert/9a8cb5f8c0ec69e6499adead0da6e95b.png)


最全的Linux教程,Linux从入门到精通

======================

1.  **linux从入门到精通(第2版)**

2.  **Linux系统移植**

3.  **Linux驱动开发入门与实战**

4.  **LINUX 系统移植 第2版**

5.  **Linux开源网络全栈详解 从DPDK到OpenFlow**



![华为18级工程师呕心沥血撰写3000页Linux学习笔记教程](https://img-blog.csdnimg.cn/img_convert/59742364bb1338737fe2d315a9e2ec54.png)



第一份《Linux从入门到精通》466页

====================

内容简介

====

本书是获得了很多读者好评的Linux经典畅销书**《Linux从入门到精通》的第2版**。本书第1版出版后曾经多次印刷,并被51CTO读书频道评为“最受读者喜爱的原创IT技术图书奖”。本书第﹖版以最新的Ubuntu 12.04为版本,循序渐进地向读者介绍了Linux 的基础应用、系统管理、网络应用、娱乐和办公、程序开发、服务器配置、系统安全等。本书附带1张光盘,内容为本书配套多媒体教学视频。另外,本书还为读者提供了大量的Linux学习资料和Ubuntu安装镜像文件,供读者免费下载。



![华为18级工程师呕心沥血撰写3000页Linux学习笔记教程](https://img-blog.csdnimg.cn/img_convert/9d4aefb6a92edea27b825e59aa1f2c54.png)



**本书适合广大Linux初中级用户、开源软件爱好者和大专院校的学生阅读,同时也非常适合准备从事Linux平台开发的各类人员。**

> 需要《Linux入门到精通》、《linux系统移植》、《Linux驱动开发入门实战》、《Linux开源网络全栈》电子书籍及教程的工程师朋友们劳烦您转发+评论




**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618542503)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

x开源网络全栈详解 从DPDK到OpenFlow**



![华为18级工程师呕心沥血撰写3000页Linux学习笔记教程](https://img-blog.csdnimg.cn/img_convert/59742364bb1338737fe2d315a9e2ec54.png)



第一份《Linux从入门到精通》466页

====================

内容简介

====

本书是获得了很多读者好评的Linux经典畅销书**《Linux从入门到精通》的第2版**。本书第1版出版后曾经多次印刷,并被51CTO读书频道评为“最受读者喜爱的原创IT技术图书奖”。本书第﹖版以最新的Ubuntu 12.04为版本,循序渐进地向读者介绍了Linux 的基础应用、系统管理、网络应用、娱乐和办公、程序开发、服务器配置、系统安全等。本书附带1张光盘,内容为本书配套多媒体教学视频。另外,本书还为读者提供了大量的Linux学习资料和Ubuntu安装镜像文件,供读者免费下载。



![华为18级工程师呕心沥血撰写3000页Linux学习笔记教程](https://img-blog.csdnimg.cn/img_convert/9d4aefb6a92edea27b825e59aa1f2c54.png)



**本书适合广大Linux初中级用户、开源软件爱好者和大专院校的学生阅读,同时也非常适合准备从事Linux平台开发的各类人员。**

> 需要《Linux入门到精通》、《linux系统移植》、《Linux驱动开发入门实战》、《Linux开源网络全栈》电子书籍及教程的工程师朋友们劳烦您转发+评论




**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618542503)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 17
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值