双非本科生进大厂,而我还在底层默默地爬树(上)

个性签名:整个建筑最重要的是地基,地基不稳,地动山摇。而学技术更要扎稳基础,关注我,带你稳扎每一板块邻域的基础。
博客主页:啊四战斗霸的博客
专栏:数据结构(C语言版)
南来的北往的,走过路过千万别错过,错过本篇,“精彩”可能与您失之交臂 la
有代码,就有注释!!!
Triple attack(三连击):Comment,Like and Collect—>Attention


数据结构三要素:逻辑结构、数据的运算、存储结构(物理结构)。存储结构不同,运算的实现方式不同。

1、树

1.1、基本概念

树是 n ( n ≥ 0 ) n(n\geq 0) n(n0)个结点的有限集合,n=0时即结点数为0,称为空树。
任意一棵非空树应满足

  • 有且仅有一个特定的称为根的结点
  • 当n>1时,其余结点可分为m(m>0)个互不相交的有限集合,其中每个集合本身又是一棵树,并且称为根结点的子树。

非空树的特性

  • 有且仅有一个根结点
  • 没有后继的结点称为叶子结点
  • 有后继的结点称为分支结点
  • 除了根结点外,任何一个结点都有且仅有一个前驱
  • 每个结点可以有0个或多个后继

树的逻辑表示法

  • 树形表示法
  • 文氏图表示法
  • 凹入表示法
  • 括号表示法

1.2、基本术语

1.2.1、结点之间的关系描述
  • 祖先结点
  • 子孙结点
  • 双亲结点(父节点)
  • 孩子结点
  • 兄弟结点
  • 堂兄弟结点
  • 路径:两个结点之间的路径只能从上往下
  • 路径长度:经过几条边
1.2.2、结点与树的属性描述

属性:

  • 结点的层次(深度)——从上往下数(默认从1开始)
  • 结点的高度——从下往上数
  • 树的高度(深度)——总共多少层
  • 结点的度——有几个孩子(分支数)注:非叶子结点的度>0,叶子结点的度=0
  • 树的度:各结点的度的最大值
1.2.3、有序树、无序树

逻辑上看,各子树是否有序,位置是否可互换
判断:具体看用树存什么,是否需要用结点的左右位置反映某些逻辑关系

  • 有序树:逻辑上看,树中的结点的各子树从左至右是有次序的,不能互换
  • 无序树:逻辑上看,树中的结点的各子树从左至右是无次序的,可以互换
1.2.4、森林

森林是 m ( m ≥ 0 ) m(m\geq 0) m(m0)互不相交的树的集合。

1.3、树的性质

  • 1、结点数=总度数+1
    结点的度——结点有几个孩子(分支数)

  • 2、度为m的数、m叉树的区别

    • 度为m的树
      • 至少有一个结点度=m
      • 一定是非空树
    • m叉树
      • 允许所有结点的度都<m
      • 可以是空树
  • 3、度为m的树第i层至多有 m i − 1 m^{i-1} mi1个结点( i ≥ 1 i\geq 1 i1
    m叉树——第i层至多有 m i − 1 m^{i-1} mi1 个 结 点 ( i ≥ 1 个结点(i\geq 1 i1

  • 4、高度为h的m叉树至多有 m h − 1 m − 1 \frac{m^{h}-1}{m-1} m1mh1个结点

  • 5、高度为h的m叉树至少有h个结点
    高度为h、度为m的树至少有h+m-1个结点

  • 6、具有n个结点的m叉树的最小高度为 ⌈ l o g m ( n ( m − 1 ) + 1 ) ⌉ \left \lceil log_{m}(n(m-1)+1) \right \rceil logm(n(m1)+1)

2、树的存储结构

2.1、双亲表示法(顺序存储)

顺序存储各个结点,每个结点中保存指向双亲的“指针”。

  • 优点:查指定结点的双亲很方便
  • 缺点:查指定结点的孩子只能从头遍历
  • 空数据导致遍历更慢
#define MaxSize 100
typedef struct
{
    
    
	ElemType data;		//存放结点的值
	int parent;			//存放双亲的位置
}PTree[MaxSize];		//PTree为双亲存储结构类型

2.2、孩子表示法(顺序+链式存储)

顺序存储各个结点,每个结点中保存孩子链表头指针

  • 优点:找孩子方便
  • 缺点:找父节点不方便

MaxSons为最多的孩子结点个数,或称为该树的度。

typedef struct
{
    
    
	ElemType data;			//结点的值
	struct node *sons[MaxSons];		//指向孩子结点
}TSonNode;			//孩子链存储结构中的结点类型

2.3、孩子兄弟表示法(链式存储)

用二叉链表存储树——左孩子右兄弟
为每个结点设计3个域:

  • 一个数据元素域
  • 一个指向该结点的左边第一个孩子结点(长子)的指针域
  • 一个指向该结点的下一个兄弟结点的指针域

孩子兄弟链存储结构实际上是把该树转化为二叉树的存储结构

typedef struct tnode
{
    
    
	ElemType data;			//结点的值
	struct tnode *hp;		//指向兄弟
	struct tnode *vp;		//指向孩子结点
}TSBNode;			//孩子兄弟链存储结构中的结点类型

2.4、树、森林与二叉树的转换

本质:用二叉链表存储森林——左孩子右兄弟。森林中各个树的根节点之间视为兄弟关系

2.4.1、森林、树转化为二叉树
  • 树中所有相邻兄弟之间加一条连线
  • 对树中的每个结点只保留它与长子之间的连线,删除与其他孩子之间的连线
  • 以树的根结点为轴心,将整棵树顺时针转动45°,使之结构层次分明
2.4.2、二叉树还原为森林、树
  • 若某结点是其双亲的左孩子,则把该结点的右孩子、右孩子的右孩子等都与该结点的双亲结点用连线连起来
  • 删除原二叉树中所有双亲结点与右孩子结点之间的连线
  • 整理由前面两步得到的树,即以根结点为轴心,逆时针转动45°,使之结构层次分明

3、树、森林的遍历

3.1、树的遍历

树的遍历运算是指按某种方式访问树中的所有结点且每一个结点只被访问一次。树的遍历方式主要有先根遍历、后根遍历和层次遍历三种。注意:树的先根遍历和后根遍历过着都是递归的。

3.1.1、先根遍历

若树非空,先访问根结点,再依次对每棵子树进行先根遍历

3.1.2、后根遍历(深度优先遍历)

若树非空,先依次对每棵子树进行后根遍历,最后再访问根结点。树的后根遍历序列与这棵树相应二叉树的中序序列相同

3.1.3、层次遍历(广度优先遍历)

1.若树非空,则根节点入队;2.若队列非空,队头元素出队并访问,同时将该元素的孩子依次入队;3.重复2的步骤直到队列为空。(用队列实现)

3.2、森林的遍历

3.2.1、先序遍历

若森林为非空,则按如下规则进行遍历:
访问森林中第一棵树的根结点;先序遍历第一棵树中根结点的子树森林;先序遍历除去第一棵树之后剩余的树构成的森林。

3.2.2、中序遍历

若森林为非空,则按如下规则进行遍历:
中序遍历森林中第一棵树的根结点的子树森林;访问第一棵树的根结点;中序遍历除去第一棵树之后剩余的树构成的森林。

猜你喜欢

转载自blog.csdn.net/weixin_64215932/article/details/124616046