【树和森林】数据结构 C++

什么是树? 树(Tree)是n(n>=0)个节点的有限集

  1. 若 n = 0, 则称为空树
  2. 若 n > 0:
  • 有且仅有一个特定的根(Root)的结点
  • 其余结点可分为m (m>=0)个互不相交的有限集T1, T2, T3 … Tm

那什么又是森林呢? 很简单, 森林是 m (m>= 0) 棵互不相交的树的集合

树的存储结构

双亲表示法 (找双亲容易, 找孩子难)

每个结点有两个域, 数据域和双亲域
数据域 (data) : 存放结点自身的信息
双亲域 (parent): 该结点的父结点的下标
如:

该结点在数组中的下标dataparent
0R-1
1A0
2B0
3C0
4D1
5E1
6F3
7G6
8H6
9I6

所以这棵树的形状为:
在这里插入图片描述
结点结构体:

typedef struct PTNode {
	TeleType data; // 数据域
	int parent; // 双亲位置域
} PTNode;

树结构:

#define MAX_TREE_SIZE 100
typedef struct{
	PTNode [nodes[MAX_TREE_SIZE]; // 结点数组
	int root;
	int n; // 结点个数
} PTree;

孩子表示法

将每个结点的孩子用单链表存储起来, 然后每个结点由组成一个线性表, 用结构体数组表示

在这里插入图片描述

所以这棵树的形状为:
在这里插入图片描述

// 孩子结构体
typedef struct CTNode {
    int child; // 记录孩子的数组下标
    CTNode* next; // 指向下一个孩子
}  *ChildPtr;

// 双亲结构体
typedef struct CTBox {
  	ElemType data; 
    ChildPtr firstchild; // 孩子链表的头指针
} CTBox;

// 树结构
typedef struct CTree {
  	CTBox nodes[MAX_SIZE]; // 结点结构体数组
    int root;
    int n;
} CTree;

孩子兄弟表示法

又名二叉树表示法, 二叉链表表示法
用二叉链表作为树的结构, 链表中的每个结点有两个指针域,分别指向第一个孩子结点, 下一个兄弟结点

在这里插入图片描述

typedef struct CSNode {
    ElemType data;
    CSNode* firstchild; // 第一个孩子
    CSNode* nextsibling; // 下一个兄弟结点
} CSNode, *CSTree;

树与二叉树的相互转化

树 -> 二叉树

记忆:兄弟相连留长子

为什么要把树转化成二叉树? 因为一般的树相对于二叉树来说比较复杂, 而我们把它转化成二叉树后, 可以利用二叉树的算法来实现对树的操作

给定一棵树, 可以找到唯一与其对应的二叉树

  1. 加线: 在相邻兄弟之间加一条线
  2. 去线: 对每个节点, 除了其左孩子外, 去除它与其他孩子之间的线(关系)

如上面的孩子兄弟表示法, 本质就是用二叉链表表示一般的树:

在这里插入图片描述

二叉树 -> 树

记忆:左孩右右连双亲,去掉原来右孩线

是树变二叉树的逆过程

  1. 加线: 若p结点是父结点f的左孩子, 则将p结点的右孩子、右孩子的右孩子…沿分支找到的所有右孩子, 都与f用线连接起来
  2. 去线: 去掉原二叉树中所有结点与右孩子的连线
  3. 调整:将结点按层次排列,使其结构清楚,形成树结构

森林与二叉树的相互转化

森林 -> 二叉树

记忆:树变二叉根相连

  1. 将各棵树分别转化成二叉树
  2. 第一棵二叉树不动,从第二棵二叉树开始,依次把后一颗二叉树的根结点作为前一颗二叉树根结点的右孩子,用线连接起来
  3. 以第一颗树的根结点为二叉树的根,适当进行结构调整

如:

在这里插入图片描述

二叉树 -> 森林

记忆:去掉根的右孩孩,孤立二叉再还原

  1. 加线:将二叉树中根结点与其右孩子连线,及沿右分支搜索到的所有右孩子间的连线全部去掉,使之变成一个个孤立的二叉树
  2. 还原:将孤立的二叉树还原成树

如:

在这里插入图片描述


全部口诀:

树变二叉树:兄弟相连留长子

二叉树变树:左孩右右连双亲,去掉原来右孩线

森林变二叉树:树变二叉根相连

二叉树变树:去掉根的右孩孩,孤立二叉再还原


树与森林的遍历

树的遍历(类似二叉树的遍历)

在这里插入图片描述

先根(次序)遍历

若树不空,则先访问根结点,然后依次(一般从左到右)先根遍历各棵子树。

遍历结果:A B C D E

后根(次序)遍历

若树不空,则先依次(一般从左到右)后根遍历各棵子树,然后访问根结点。

遍历结果:B D C E A

层次遍历

若树不空,则从上到下一层一层访问每个结点

遍历结果:A B C E D


森林的遍历

将森林看作三部分:

  1. 森林中第一棵树的根节点
  2. 森林中第一棵树的子树森林
  3. 森林中其他树构成的森林

如:

在这里插入图片描述

先序遍历

若森林不空,则

  1. 访问森林中第一棵树的根结点;
  2. 先序遍历森林中第一棵树的子树森林;
  3. 先序遍历森林中(除第一棵树之外)其余树构成的森林。

中序遍历

若森林不空,则

  1. 中序遍历森林中第一棵树的子树森林;
  2. 访问森林中第一棵树的根结点;
  3. 中序遍历森林中(除第一棵树之外)其余树构成的森林。

这份笔记是我根据B站“青岛大学-王卓”王老师的教学视频写的,王老师讲的很好,感兴趣的话, 读者可以去看看

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值