树的定义、存储结构及森林的有关概念

什么是树?

树可以用几种不同的方式定义,一种自然的定义树的方法是递归。一棵树是一些节点的集合,这个集合可以是空集,当非空时,则一棵树由根节点root以及0个或多个非空的子树组成,这些子树中的每一棵的根都由来自根root的一条边连接。每一棵子树的根叫做root的儿子,根root是每一棵子树根的父亲。root没有父亲节点。

T1到T5是root的子节点,root是它们的父节点。

下面看一棵更复杂的树:

没有儿子的节点称为树叶(叶节点):A、B、E、D、T4、T5

具有相同父亲的节点称为兄弟节点:例如,A和B为兄弟节点,但A和D不是兄弟节点

T2为E的祖父节点

从节点n1到nk的一条路径定义为n1到nk的一个序列,在这条路径中,ni是ni1+1的父亲节点。这个路径的长为路径上边的个数。每个节点有一条长为0的路径到它自己。

对任意节点ni,它的深度是从根到ni的唯一路径的长度,根的深度为0。ni的高度是,从ni到一片树叶的最长路径的长,所以叶节点的高度为0.

如果有n1到n2的一条路径,那么n1是n2的一位祖先,n2是n1的一个后裔,如果路径长不为0,那么n1是n2的一个真祖先,n2是n1的一个真后裔。

树的实现:定义一个结构体,结构体中包含三部分:该节点的值,指向一个孩子的指针,指向下一个兄弟的指针。通过这种方法,就能够访问到树的每一个节点。

struct Tree{
    valtype val;//节点值
    ptr nextbro;//下一个兄弟
    ptr firstchild;//第一个孩子
};

树的遍历:

①先序遍历:先处理父亲节点,再处理儿子节点

②后序遍历:先处理儿子节点,再处理父亲节点

树的存储结构:

1. 双亲表示法

  

由于树中的任何结点都只能有一个父节点,所以可以在每个节点中将其父节点表示出来。

typedef struct TreeNode {
	int val;//该结点的关键字
	struct TreeNode* father;//该结点的父节点
};

也可以使用二维数组,数组中每一行表示一个结点,第一列表示结点的关键字,第二列表示其父节点的下标。

//没有父结点的结点的第二列设为-1
int Tree[NumofTreeNode][2];

2. 孩子表示法

  

d表示树中结点孩子最多的孩子的数量。这种结构可以使用结构体或是数组来实现。但是并不是每个结点都有这么多孩子,所以会有大量的空间被浪费。

 

如果d表示的是该结点孩子的数量,也就是说,每个结点中包含的指向孩子的域的数量是不同的,那么就可以节省空间,但是这种方法的实现较复杂。

 

另一种方法是使用链表将孩子结点串起来,这种方法可以使用数组加链表来实现。

 

还可以在结点中增加一个指向其父节点的域。

3. 孩子兄弟法

在这种方法中,每个结点有两个指针域,左指针指向该结点的第一个孩子,右指针指向给节点的兄弟结点。可以使用数组或二叉链表来实现。

struct TreeNode {
	int val;
	struct TreeNode* firstchild;//指向第一个孩子
	struct TreeNode* nextsibling;//指向下一个兄弟
};

还可以使用二维数组来实现,这个数组有三列,后面两列分别表示第一个孩子和下一个兄弟。

什么是森林?

森林是树的集合,森林中可以有0或者n个树。

如果将森林中的所有树的根节点都看作是兄弟结点的话,就可以使用孩子兄弟法将森林转换成一棵二叉树。这个过程是一个递归的过程,步骤如下:

首先,生成的二叉树的根是森林中第一棵树的根;

第一棵树的左子树是其子树森林生成的二叉树,右子树是森林中余下的树生成的二叉树。

如果二叉树是使用孩子兄弟法表示的,那么二叉树就可以转换成森林,这也是一个递归的过程,步骤如下:

首先,森林中第一棵树的根是此时二叉树的根;

第一棵树的孩子是二叉树的左子树转换成的子树森林,其兄弟结点是二叉树的右子树转换成的森林。 

森林的遍历:

1. 先序遍历:首先遍历第一棵树的根节点,然后遍历第一棵树的子树森林,最后遍历除去第一棵树余下的树组成的森林。当森林转换成二叉树时,这就是二叉树的先根遍历。

2. 中序遍历:首先遍历第一棵树的子树森林,然后遍历第一棵树的根节点,最后遍历除去第一棵树余下的树组成的森林。当森林转换成二叉树时,这就是二叉树的中序遍历。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值