树和森林
树的存储结构
一 双亲表示法
使用一维数组,每个元素有两个域,数据域和父结点索引域
数据结构定义:
#define size 10
typedef struct
{
char data;
int parent;
} Node;
Node slist[size];
图示:
特点:
找父结点容易,找结点 的孩子麻烦,需遍历整张表。
二 孩子链表表示法
使用一维数组存储树中所有节点,每个元素有两个域数据域和第一个孩子节点的指针域
孩子节点也有两个域分别是自身对应的索引域以及下一个孩子节点的指针域
数据结构定义:
# define MAXND 20
typedef struct bnode
{int child;
struct bnode *next;
}node,*childlink;
typedef struct
{
char data;
childlink hp;
}headnode;
headnode link[MAXND];
图示:
特点:
查找子节点方便,查找父结点困难
双亲孩子表示法
为了接查找父结点困难的问题,可以在数组元素中增加一个域存储父结点的索引
数据结构定义:
# define MAXND 20
typedef struct bnode
{
int child;
struct bnode *next;
}node,*childlink;
typedef struct{
char data;
int parent; childlink hp;
}headnode;
headnode link[MAXND];
图示:
三 孩子兄弟表示法(二叉链表表示法)
使用链表存储树中的节点,链表中每个元素有三个域分别为第一个孩子指针域
,数据域
,下一个兄弟指针域
节点组成:
数据结构定义:
Typedef struct tnode
{
int data;
struct tnode *son,*brother;
}*Tree;
图示:
特点:
-
数据结构定义与二叉树的二叉链表表示法安全相同,但是指针所表示的含义是不同的
-
查找父结点需遍历链表
树/森林与二叉树之间的转换
一般树转换二叉树
转换方法:
- 个兄弟节点之间添加连线
- 对任一节点,除最左孩子之外,抹掉该节点与其他子节点的各枝(取消连线)
- 以根节点为中心,将连线顺时针转45度
图示:
一棵树的孩子兄弟链表示法与将该树转为二叉树后的二叉链表表示法存储结构完全相同,仅节点中指针含义不同
设有以下树(左),并将其转换为二叉树(右):
使用孩子兄弟表示法存储以上树得到存储结构如图(左)
使用二叉链表表示法存储转换后的二叉树得到结构如图(右)
森林转换二叉树
转换方法:
- 将每棵树转换为对应的二叉树
- 将第一步得到的各二叉树的根节点看作是兄弟节点,加连线,以最左侧根节点作为中心将根节点连线顺时针旋转45度
图示:
二叉树还原为一般树
明确:根节点没有右孩子的二叉树可转为一般树
还原方法:
- 从根节点起
- 当前节点的左孩子和左孩子右枝上的所有节点作为当前节点的孩子节点
- 重复第一步
也是树转二叉树的逆运算即以根节点为中心所有节点逆时针旋转45度
图示:
二叉树还原为森林
明确:根节点有右孩子的二叉树可转为森林
还原方法:
- 根节点右枝上的每一个节点作为一个的根节点
- 将拆开后的二叉树按
二叉树还原为一般树
的方法转换为一般树
也是森林转二叉树的逆运算
图示:
树的遍历
先序遍历:先访问根节点,然后依次先序遍历根的每个子树
后序遍历:先依次遍历每棵子树,最后访问根节点
层次遍历:从上到下从左到右依次遍历所有节点
由于子节点个数不确定所以没有无法实现中序遍历
示例:
上图对应的遍历顺序
先序:ABCDE
后序:BDCEA
层次:ABCED
树的遍历结果与转为二叉树后的遍历结果对应关系
树 => 二叉树
先序 == 先序
后序 == 中序
森林的遍历
先序遍历:依次使用先序遍历森林中每棵树
中序遍历:对每棵树按照先子后根的方式遍历每个节点
之所以叫中序: 因为 树的后序==树转二叉树的中序
示例:
上图对应的遍历顺序
先序:ABCDEFGHJI
中序:BCDAFEJHIG