在前面已经介绍过了二叉树的存储结构,那么对于一般的树来说,他的存储结构又该是怎么样的呢。
树的存储结构
树存储结构就是指能存储树中个结点的数据信息,还要能反映树中个结点之间的相互逻辑关系,下面将介绍几种常用的存储结构。
双亲表示法
根据树的定义,每个节点有且只有一个前驱元素, 因此我们可以利用类似静态链表的思想来用一个一维数组存储树中的结点,数组中的下标代表树中的结点编号,然后存储的是双亲结点的下标。
这种存储方式,如上图所示,适用于查找双亲,类型描述如下:
#define MAXSIZE 100
typedef int ElemType;
typedef struct PTNode //结点结构
{
ElemType data;
int parent; //双亲下标
}PTNode;
typedef struct //树结构
{
PTNode nodes[MAXSIZE];
int r,n; //结点数和根的位置
}PTree;
这种存储方式在寻找双亲时是比较方便的,但是如果要寻找孩子结点的位置时就需要遍历整个数组了
孩子表示法
孩子表示法就是用一个一维数组,加若干链来表示。数组的每一位元素都由两个域组成,一个域存放结点信息,另一个存放指向该结点孩子组成的单链表的首位置。
#define MAXSIZE 100
typedef char ElemType;
typedef struct CTNode //孩子结点
{
int child;
struct CTNode *next;
}*ChildPtr;
typedef struct
{
ElemType data;
ChildPtr firstChild; //孩子链的头指针
}CTBox;
typedef struct
{
CTBox nodes[MAXSIZE];
int n,r; //结点数和根的位置
}CTree;
与双亲表示法不同的事,这种表示法,虽然能很好的查找到孩子结点,但是对于双亲结点的查找来说还是不方便的.
孩子兄弟表示法
孩子兄弟表示法用的是二叉链表作为存储结构,二叉链表的一个结点包括两分,一个是数据域,一个是指针域,指针域里又包括,指向第一个孩子结点的指针,指向该结点的兄弟结点的指针。
typedef char ElemType;
typedef struct CSNode
{
ElemType data;
struct CSNode *firstChild;
struct CSNode *nextSibling;
}CSNode,*CSTree;
这里由于用的是二叉链表的表示所以和二叉树的二叉链表表示方式是差不多的,只是指针域的意义稍有不同。
树和森林与二叉树的转换
由于孩子兄弟表示法和二叉树的二叉链表的存储形式是一样的,所以就可以用二叉链表作为媒介转化为二叉树。从孩子兄弟法的描述可以看出,左结点指向的是孩子结点,右结点指向的是兄弟结点,但由于根结点没有兄弟结,所以树所对应的二叉树的右子树一定为空。
方法:
- 树中所有相邻兄弟之间加一条线
- 除去每个结点的第一个孩子保留外,把其他与孩子结点间的连线去除
-
旋转树,调整角度
那么同样的对应的森林转化为二叉树就是,把每棵树的跟结点都看成是兄弟,那么就可以按照对应的把森林转化为二叉树。