树和森林
树
非线性结构:1对n
结点之间有分支,具有层次关系
树(Tree)是n (n≥0)个结点的有限集
- n = 0,称为空树
- n >0
- 有且仅有一个特定的称为根(Root)的结点
- 其余结点可分为m (m≥0)个互不相交的有限集T1,T2,T3,...Tm,其中每一个集合本身又是一棵树,并称为根的子树(SubTree)
树的其他表示方式:
-
集合嵌套:
-
凹入表示:
-
广义表表示:
(A(B(E(K,L)F),C(G),D(H(M),I,J)))
树由数据元素和指向子树的分支所构成
根结点:无前驱结点的结点
结点的度:结点拥有的子树数
树的度:树内各结点度的最大值
树的深度/高度:树中结点的最大层次
叶子阶段/终端结点:度=0
分支结点/非终端结点:度≠0 (可包含根节点)
内部结点:根节点以外的分支结点
结点子树的根称为该结点的孩子,该结点称为孩子的双亲, 有共同双亲的结点称为兄弟, 兄弟在同一层的结点称为堂兄弟 ,从根到该结点所经过的所有结点称为该结点的祖先,以某结点为根的子树中的任一结点称为该结点的子孙
有序树:树中结点的各子树从左至右有次序(最左边为第一个孩子)
无序树:树中各结点子树无次序
线性结构
第一个数据元素 无前驱
最后一个数据元素 无后继
其它数据元素,一个前驱,一个后继
一对一
树结构
根结点(只有一个) 无双亲
叶子结点(可以有多个) 无孩子
其它结点—中间结点 一个双亲,多个孩子
一对多
树的存储结构
双亲表示法
定义结构数组,存放树的结点,每个结点包含数据域(存放结点本身信息)和双亲域(结点的双亲在数组中的位置)
例:
特点:易找双亲,难找孩子
结点结构:data+parent
定义:
#define MAXSIZE 100
typedef struct PTnode{
char data;
int parent; //双亲位置域
}PTNode;
typedef struct {
PTNode nodes[MAXSIZE];
int r,n; //根结点位置和结点个数
}PTree;
孩子链表表示法
把每个结点的孩子结点排列起来,看成一个线性表,用单链表存储
则n个结点有n个孩子链表
n个头指针又组成一个线性表用顺序表存储
例:
孩子结点结构:child+next
特点:找孩子容易,找双亲难
定义:
//孩子结点结构
typedef struct CTnode{
int child;
struct CTnode *next;
}*ChildPtr;
//双亲结点结构
typedef struct {
char data;
ChildPtr fishchild; //孩子链表头指针
}CTBox;
//树结构
typedef struct {
CTBox nodes[MAXSIZE];
int n,r; //结点数和根结点位置
}CTree;
带双亲的孩子链表:在孩子链表基础上增加双亲域
孩子兄弟表示法
用二叉链表作树的存储结构,链表中每个结点的两个指针域分别指向第一个孩子结点和下一个兄弟结点
例:
定义:
typedef struct CSnode{
char data;
struct CSnode *fishchild,*nextsibling;
}CSNode,*CSTree;
树与二叉树的转换
树和二叉树都可以用二叉链表作存储结构,因此以二叉链表作为媒介可以导出树与二叉树之间的对应关系
给定一棵树,可以找到唯一一棵二叉树与之对应
例:
将树转换为二叉树
-
在兄弟之间加一连线
-
加线的结点去掉与双亲的连线(除其左孩子)
-
以树的根结点为轴心顺时针旋转45°
兄弟相连留长子
例:
将二叉树转换为树
-
若p结点是双亲结点的左孩子,则将p的右孩子,右孩子的右孩子....沿分支找到的所有右孩子,都与p的双亲用线连起来
-
抹掉原二叉树中双亲与右孩子之间的连线
-
将结点按层次排列,形成树结构
左孩右右连双亲,去掉原来右孩线
例:
树的遍历
先根遍历
若树不空,则先访问根结点,然后依次先根遍历各棵子树
后根遍历
若树不空,先依次后根遍历各棵子树,然后访问根结点
层次遍历
若树不空,自上而下,自左而右依次访问树中的每个结点
例:
先根遍历:ABCDE
后根遍历:BDCEA
层次遍历:ABCED
森林
m(m>=0)棵互不相交的树的集合
把根结点删除,树就变成了森林;给森林中各子树加上一个双亲结点,森林就变成了树
树一定是森林 ,但森林不一定是树
森林与二叉树的转换
森林转化为二叉树
-
将各棵树转化成二叉树
-
每棵树的根结点用线相连
-
以第一棵树的根结点为二叉树的根,以根结点为结点顺时针旋转
树变二叉根相连
例:
二叉树转化成森林
-
二叉树中根结点与其右孩子连线,及沿右分支搜索到的所有右孩子间连线全部抹掉,使之变成孤立的二叉树
-
将孤立的二叉树还原成树
去掉全部右孩线,孤立二叉再还原
例:
森林的遍历
将森林分成三个部分:
- 森林中第一棵树的根结点
- 森林中第一棵树的子树森林
- 森林中其他树构成的森林
先序遍历
若森林不空,则
- 访问森林第一棵树的根结点
- 先序遍历第一棵子树的森林
- 先序遍历其余树构成的森林
依次从左至右对森林中的每棵树进行先根遍历
中序遍历
若森林不空,则
- 中序遍历第一棵子树的森林
- 访问森林第一棵树的根结点
- 中序遍历其余树构成的森林
依次从左至右对森林中的每棵树进行后根遍历
例:
先序遍历:ABCDEFGHIJ
中序遍历:BCDAFEHJIG