树和森林的存储表示
(1)树的表示法-双亲表示法
第一列为结点位置,第二列为结点,第三列为结点双亲的位置
优点:方便找双亲(向上找)
typedef char TElemType;
#define MAX_TREE_SIZE 100
typedef struct PTNode {
TElemType data;
int parent;//下标
} PTNode;
typedef struct {
PTNode nodes[MAX_TREE_SIZE];
int r, n;
}PTree;
(2) 树的表示法-多重链表表示法
链表为孩子的结点位置
优点:方便找孩子(向下找)
typedef struct CTNode{
int Child; //孩子结点的下标
struct CTNode* next;//下一孩子
}*ChildPtr;
typedef struct {
TElemType data;
int parent; ChildPtr firstchild;
} CTBox;
typedef struct {
CTBox nodes[MAX_TREE_SIZE];
int n, r;
} CTree;
(3)树的表示法-孩子兄弟表示法(二叉链表表示法)
左边为孩子,右边为兄弟。
优点:可以知道树的形状
typedef struct CSNode{
TElemType data;
struct CSNode *firstchild;
struct CSNode *nextsibling;
} CSNode, * CSTree;
森林的表示法【补充】
typedef struct CSNode{
TElemType data;
struct CSNode *firstchild;
struct CSNode *nextsibling;
} CSNode, * CSTreeOrForest;
树和森林的操作实现
树
树的先根序遍历
树不空,先访问根节点,然后依次遍历各子树
树的后根序遍历
树不空,先遍历各子树,再遍历根节点
按层次遍历
树不空,自上而下自左至右访问结点
先根遍历后面多了一个D
森林
森林先序遍历
森林不空,访问第一部分,然后第二部分,最后第三部分
森林中序遍历
森林不空,访问第二部分,然后第一部分,最后第三部分
树没有中根遍历,因为无法判断所有子树的中间位置。
森林(含树)求深度—分而治之
递归边界: 空森林深度为0
递归关系:大森林深度为首颗树的深度和余树森林的深度取最大值;
余树森林深度可递归得到,首颗树深度无法递归(不一定严格小)
首颗树的深度为子树森林深度加1;子树森林深度递归可得
int TorFDepth(CSTreeOrForest F) {
if(!F) return 0;
else {
d_FstT = TorFDepth( F->firstchild )+1;
d_SubF =TorFDepth( F->nextsibling);
if(d_FstT >= d_SubF) return d_FstT;
else return d_SubF;
}
}
补:由树的先根和后根遍历序列确定树
方法一(间接法,借助二叉链表):树的先根序列对应二叉链表的先序序列、后根序列对应二叉链表的中序序列,由先序序列与中序序列可确定出二叉链表,再根据此二叉链表按照孩子兄弟表示法的含义可得此二叉链表对应的树
方法二(直接法,根据先根后根):先根序列中第1个X一定是整颗树的根结点,而后根序列中唯有遍历完X的所有子树后方访问X,故X必然出现在最后;先根序列中第二个顶点必然是第一个子树的根结点,后根序列中该结点前的结点为此子树中各结点;除去第一颗子树中的结点后,先根序列中第一个结点必为第二颗子树的根结点,而后根序列中此结点前的结点构成第二颗子树,以此类推,最终可确定
补:由森林的先序和中序遍历序列确定森林
方法一(间接法,借助二叉链表):森林的先序序列对应二叉链表的先序序列、中序序列对应二叉链表的中序序列,由先序序列与中序序列可确定出二叉链表,再根据此二叉链表按照孩子兄弟表示法的含义可得此二叉链表对应的森林
方法二(直接法,根据先根后根):先序序列中第1个X一定是第一颗树的根结点,而中序序列中在遍历完第一颗树的最后访问X,故中序序列中X之前的结点构成森林的第一颗树,这些结点在先序和中序序列中的出现次序即为第一颗树的先根序列和后根序列,根据树的确定方法可得第一颗树;除去第一颗树的结点后,先序序列中余下的第一个结点为第二颗树的根结点,中序序列中该结点前结点的构成第二颗树,依次类推,最终可得森林