数据结构学习笔记——树的存储结构以及树森林与二叉树之间的转换
Posted 晚风(●•σ )
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构学习笔记——树的存储结构以及树森林与二叉树之间的转换相关的知识,希望对你有一定的参考价值。
目录
一、树的存储结构
树的存储结构中反映的是一棵树中各结点之间的关系,在存储中,不仅存储树中每个结点的值,还存储各结点之间的关系,主要有三种存储结构,分别是双亲表示法、孩子链表示法和孩子兄弟表示法。
(一)双亲表示法
双亲表示法是通过采用一维数组来存储树中的结点,其中每个结点被赋予一个结构体类型,包含data域和parent域,分别存储结点的数据域
和存储该结点双亲的数组下标
。
#define MAXSIZE 100
typedef struct
int data; //数据域
int parent; //双亲位置域
ParNode[MAXSIZE];
例如,下图该树,通过双亲表示法进行存储,规定从数组下标为0开始存储,根结点下标为0,同时设根结点的parent域为-1:
通过双亲表示法中可以很容易地找到每个结点的双亲和祖先,但是其缺点是若寻找结点的孩子结点或兄弟结点就较为麻烦,需遍历整个数组。
(二)孩子链表表示法
将所有结点存放在一个顺序表
中,每个数据元素有两个域,分别是该结点的数据域和存放该结点的第一个孩子的地址,同时为树中每个结点都构建一个单链表
,它也有两个域,分别是存放该孩子结点在顺序表中的数组下标和存放下一个孩子的地址。
#define MAXSIZE 100
/*顺序表定义*/
typedef struct
int data; //数据域
ChildNode *children; //第一个孩子的地址
Head;
/*单链表定义*/
typedef struct Node
int address; //该孩子结点在顺序表中的数组下标
struct Node *next; //下一个孩子的地址
ChildNode;
Head T[MAXSIZE]; //建立顺序表头结构
例如,通过孩子链表表示法进行存储上树,规定顺序表下标为0的位置存放根结点:
通过孩子链表表示法可以很容易地找到该结点的孩子结点,但是若要找到结点的双亲则较为麻烦,需遍历n个结点中孩子链表指针域所指向的n个孩子链表。
(三)孩子兄弟表示法
孩子兄弟表示法是采用二叉链表,其中包含三个域,分别是数据域和两个指针,即*child指向第一个孩子结点的地址、*brother指向该结点的下一个兄弟结点的地址。
typedef struct Node
int data; //数据域
struct Node *child,*brother; //第一个孩子结点的地址和下一个兄弟结点的地址
ChildBNode;
例如,通过孩子兄弟表示法进行存储上树:
这种方法的缺点是若从当前结点查找其双亲结点较为麻烦,解决方法是为每个结点增设一个parent域用于指向其父结点。
二、树、森林与二叉树的转换
(一)树转换成二叉树
例如,下图是一棵树,将其转换成二叉树:
1、首先为树中所有兄弟结点之间连线:
2、对树中每个结点只保留它与左边第一个孩子结点之间的连线,其余连线都删除:
3、以根结点为轴心,顺时针旋转45°,即可得到下图二叉树:
我们可以得出,一棵树转换为二叉树的途中,转换之后的右孩子结点是其原本的兄弟,例如结点C、D原本是兄弟,然后变成了B、C的右孩子,转换之后的二叉树的根结点无右子树。
(二)二叉树还原成树
二叉树还原成树的前提是该二叉树的根结点无右子树
,将上图二叉树还原成树的步骤如下:
1、若某结点的左孩子有右子树,则在该结点与其左孩子的右子树的右分支上结点连线,例如结点A的左孩子B有右子树,则在结点A和其左孩子的右子树的右分支上连线:
2、删除各结点右子树的右分支与其父结点连线(图中橙线):
删除后:
3、旋转整理即可还原得到树:
(三)森林转换成二叉树
例如,下图是一棵森林,将其转换成二叉树:
1、将该森林中每棵树转换为二叉树,为各个树中所有兄弟结点之间连线:
2、每棵树的根结点也可以视为兄弟,将其连线:
3、然后对树中每个结点只保留它与左边第一个孩子结点之间的连线,其余连线都删除其余连线都删除:
4、以第一棵树的根结点为轴心,顺时针旋转45°,整理后,即可得到下图二叉树:
(四)二叉树还原成森林
将上图二叉树还原成森林的步骤如下:
1、若某结点是其双亲的左孩子,则将该结点的右孩子、右孩子的右孩子等等都与该结点的双亲结点连接:
2、删除二叉树中所有双亲结点与其右孩子结点的连线:
3、整理所得到的树和森林:
以上是关于数据结构学习笔记——树的存储结构以及树森林与二叉树之间的转换的主要内容,如果未能解决你的问题,请参考以下文章