一,定义
树的定义:树是n(n>=0)个结点的有限集.若n = 0,称为空树;
若n > 0 则:1,有且仅有一个特定的称为根的结点,2,其余结点可分为m(m>=0)个互不相交的有限集T1,T2,T3.....,Tm,
森林的定义:是m(m>=0)棵互不相交的树的集合.
二,树的存储结构
1:双亲表示法
实现:定义结构数组,存放树的结点,每个结点含两个域,数据域(存放结点本身信息),双亲域(指示本结点的双亲结点在数组中的位置)
双亲域-1表示根结点,B,C,D的双亲都是0号位置的A,E,F的双亲是位置为1号位置的B,G的双亲是位置在3号位置的D,H的双亲是位置在6号位置的G.
这种存储方式,要查找双亲很容易,直接通过双亲域的值,就可以查找到.但是要查找孩子比较麻烦,其元素类型表示方式为:
typedef struct PTNode{
TElemType data;
int parent;//双亲位置域
}PTNode;
所以,树的结构就是一个包含上面类型数据的一个数组
#define MAX_TREE_SIZE 100
typedef struct{
PTNode nodes[MAX_TREE_SIZE];
int r;//根结点位置
int n;//结点个数,数组的元素个数
}PTree;
2,孩子链表
把每个结点的孩子结点排列起来,看成是一个线性表,用单链表存储
则n个结点有n个孩子链表(叶子的孩子链表为空表).而n个头指针又组成一个线性表,用顺序表(含n个元素的结构数组)存储.
孩子结点结构:
typedef struct CTNode{
int child;//下标
struct CTNode * next;
}*ChildPtr;
双亲结点结构:
typedef struct(
TElemType data;
ChildPtr firstchild;//孩子链表头指针
}CTBox;
所以,最终树的结构为:
typedef struct{
CTBox nodes[MAX_TREE_SIZE];
int n;//结点数
int r;//根结点下标
}CTree;
这个结构特点:找孩子容易,找双亲难.为了又能找孩子,又方便找双亲,就有了下面的:带双亲的孩子链表
带双亲的孩子链表
这样,不管是找孩子还是找双亲,都比较容易了!!!(牺牲空间换取时间)
3,孩子兄弟表示法(二叉链表存储法)
实现:用二叉链表作为树的存储结构,链表中每个结点的两个指针域分别指向其第一个孩子结点和下一个兄弟结点
typedef struct CBNode{
ElemType data;
struct CBNode * firstchild;
struct CBNode * nextbrother;
}CBNode, *CBTree;
上面树的结构用孩子兄弟表示法,展现出来就是这样: