1、双亲表示法

双亲表示法声明如下:

typedef int TPosition; //结点的位置类型为整型
struct  NodeType
   ElemType  data ;    //该结点的数据
   TPosition Parent;   //该结点的父亲的数组下标,对于根结点该域为0
 }
 struct TreeType
   int NodeCount;      //树的结点的总数目
   NodeType Node[MaxNodeCount];  //存储树的结点
 }




图1 一棵需要存储的树

用一维数组存储它,得到树的双亲表示法,如下表:

结点序号 1 2 3 4 5 6 7 8 9 10 11 12 13 
data A B E F C G K L D H I J M 
parent 0 1 2 2 1 5 6 6 1 9 9 9 12 


由于树中每个结点的父亲是唯一的,所以上述的父亲数组表示法可以唯一地表示任何一棵树。在这种表示法下,寻找一个结点的父结点只需要O(1)时间。在树中可以从一个结点出发找出一条向上延伸到达其祖先的道路,即从一个结点到其父亲,再到其祖父等等,这就可以求出根。求这样的道路所需的时间正比于道路上结点的个数。在树的双亲表示法中,对于涉及查询儿子和兄弟信息的树操作,可能要遍历整个数组。为了节省查询时间,可以规定指示儿子的数组下标值大于父亲的数组下标值,而指示兄弟结点的数组下标值随着兄弟的从左到右是递增的。

2、孩子表示法

在树中,每个结点有若干个指针域,指向其孩子。由于孩子的数目不一,所以可以有两种表示方法:

方法一:  data child1 child2 …… childd 


这种表示法,所有的结点都是同构的,其中d为树的度。由于树中很多结点的度小于d,所以浪费了很多空间

方法二:  data degree child1 child2 …… childn 


在这种表示法中,degree指示了该结点有几个孩子,n为结点的度,不同的结点所占的格式不同,所以能够节约空间,但操作不便。

树的另一种常用的表示方法就是儿子链表表示法。这种表示法用一个线性表来存储树的所有结点信息,称为结点表。对每个结点建立一个儿子表。儿子表中只存储儿子结点的地址信息,可以是指针,数组下标甚至内存地址。由于每个结点的儿子数目不定,因此儿子表常用单链表来实现。下图是一个儿子链表表示法的示意图 



3、孩子兄弟表示法

树的左儿子右兄弟表示法又称为二叉树表示法或二叉链表表示法。每个结点除了data域外,还含有两个域,分别指向该结点的最左儿子和右邻兄弟。这种表示法常用二叉链表实现,因此又称为二叉链表表示法。若用指针实现,其类型定义为:

typedef   NodeType  *TPosition;
struct NodeType
     ElemType data;
     TPosition Leftmost_Child,Right_Sibling;
 }



用树的左儿子右兄弟表示法可以直接实现树的大部分操作,只有在对树结点作Parent操作时需遍历树。如果要反复执行Parent操作,可在结点记录中再开辟一个指向父结点的指针域,也可以利用最右儿子单元中的Right_Sibling作为指向父结点的指针(否则这里总是空指针)。当执行Parent(v)时,可以先通过Right_Sibling逐步找出结点v的最右兄弟,再通过最右兄弟的Right_Sibling(父亲指针)找到父结点。这个结点就是结点v的父亲。在这样的表示法下,求一个结点的父亲所需要的时间正比于该结点右边的兄弟个数。不过,这时每个记录中需要多用一位(bit)空间,用以标明该记录中的right_sibling是指向右邻兄弟还是指向父亲。

考虑到对于现在的计算机,内存已经不是很重要的限制因素了。我们下面就采取增加一个parent域的方案,以改进左儿子右兄弟表示法中Parent操作的效率。因此重新定义树的类型如下:

typedef  NodeType *TPosition;
struct NodeType
   ElemType data;
   TPosition Parent,Leftmost_Child,Right_Sibling; //增加一个Parent域
 }




如果是 二叉树,还可以用 一维数组表示,父节点i(i从1开始) , 左孩子2i,右孩子 2i+1;