树的抽象数据类型和几种表示法

/*
树(Tree)
6.3 树的抽象数据类型
相对于线性结构,树的操作就完全不同了,这里我们给出一些基本和常用操作。
ADT 树(tree)
Data
    树是由一个根节点和若干棵子树构成。树中结点具有相同数据类型及层次关系。
Operation
    InitTree(*T);           构造空树T
    DestroyTree(*T);        销毁树T
    CreateTree(*T, definition);     按definition中给出树的定义来构造树
    ClearTree(*T);          若树T存在,则将树T清空为空树
    TreeEmpty(T);           若T为空树,返回true,否则返回false
    TreeDepth(T);           返回T的深度
    Root(T);                返回T的根结点
    Value(T, cur_e);        cur_e是树T中一个结点,返回此结点的值
    Assign(T, cur_e, value);    给树T的结点cur_e赋值为value
    Parent(T, cur_e);       若cur_e是树T的非根结点,则返回它的双亲,否则返回空
    LeftChild(T, cur_e);    若cur_e是树T的非叶结点,则返回它的双亲,否则返回空
    RightSibling(T, cur_e); 若cur_e有右兄弟,则返回它的右兄弟,否则返回空
    InsertChild(*T, *p, i, c);  其中p指向树T的某个结点,i为所指结点p的度加上1,非空树c与T不相交,
                                操作结果为 插入c为树T中p指结点的第i棵子树
    DeleteChild(*T, *p, i);     其中p指向树T的某个结点,i为所指结点p的度,
                                操作结果为 删除T中p所指结点的第i棵子树
endADT
*/

/*
6.4 树的存储结构
    说到存储结构,就会想到我们前面章节讲过的顺序存储和链式存储两种结构。
    先来看看顺序存储结构,用一段地址连续的存储单元依次存储线性表的数据元素。这对于线性表来说是很自然的,
对于树这样一对多的结构呢?
    树中某个结点的孩子可以有多个,这就意味着,无论按何种顺序将树中所有结点存储到数组中,结点的存储位置
都无法直接反映逻辑关系,你想想看,数据元素挨个存储,谁是谁的双亲,谁是谁的孩子呢?简单的存储结构是不能
满足树的实现要求的。
    不过充分利用顺序存储和链式存储结构的特点,完全可以实现对树的存储结构的表示。我们这里要介绍三种不同的
表示法:双亲表示法、孩子表示法、孩子兄弟表示法。
*/


/*6.4.1 双亲表示法*/

//树的双亲表示法结点结构定义
#define MAX_TREE_SIZE 100
//树节点的数据类型,目前暂定为整形
typedef int TElemType;
//节点结构
typedef struct PTNode
{
    //结点数据
    TElemType data;
    //双亲位置,通常讲的父节点
    int parent;
} PTNode;

//树结构
typedef struct
{
    //结点数组
    PTNode nodes[MAX_TREE_SIZE];
    //跟的位置和结点数
    int r, n;
} PTree;

/*6.4.2 孩子表示法*/
/*
具体的办法是,把每个结点的孩子结点排列起来,以单链表作存储结构,则n个结点有n个孩子链表,如果是
叶子结点则此单链表为空。然后n个头指针又组成一个线性表,采用顺序存储结构,存放进一个一维数组中。
见原书 284页 图6-4-4
为此,设计两种节点结构,
一个是 孩子链表的孩子结点;其中child是数据域,用来存储某个结点在表头数组中
的下标。next是指针域,用来存储指向某节点的下一个孩子结点的指针。
另一个 是表头数组的表头结点,其中data是数据域,存储某结点的数据信息。firstchild是头指针域,存储
该结点的孩子链表的头指针。
*/

/*树的孩子表示法结构定义*/
#define MAX_TREE_SIZE 100
//孩子结点
typedef struct CTNode
{
    int child;
    struct CTNode *next;
} *ChildPtr;
//表头结构
typedef struct 
{
    TElemType data;
    ChildPtr firstchild;
} CTBox;
//树结构
typedef struct 
{
    /*结点数组*/
    CTBox nodes[MAX_TREE_SIZE];
    int r,n;
} CTree;

/*
这样的结构对于我们要查找某个结点的某个孩子,或者找某个结点的兄弟,只需要查找这个节点的孩子单链表即可
但是,这也存在着问题,我如何知道某个结点的双亲是谁呢?比较麻烦,需要整棵树遍历才行 ,难道就不可以把双亲
表示法和孩子表示法综合一下吗?
当然可以了 看原书 图6-4-5(双亲孩子表示法)
*/

/*
6.4.3 孩子兄弟表示法
    刚才我们分别从双亲的角度和孩子的角度研究树的存储结构,如果我们从树结点的兄弟的角度考虑又会如何呢?
当然,对于树这样的层级结构来说,只研究结点的兄弟是不行的,我们观察后发现,任意一棵树,他的结点的第一个
孩子如果存在就是唯一的,它的右兄弟如果存在也是唯一的。因此我们设置两个指针,分别指向该结点的第一个孩子和
此结点的右兄弟。
*/
//结构定义代码如下
//树的孩子兄弟表示法结构定义
typedef struct CSNode
{
    TElemType data;
    struct CSNode *firstchild,*rightsib;
} CSNode, *CSTree;

/*
这种表示法,给查找某个结点的某个孩子带来了方便,只需要通过firstchild找到此结点的长子,然后通过长子结点
的rightsib找到它的二弟,接着一直下去,直到找到具体的孩子。当然,如果想找某个结点的双亲,这个表示法
也是有缺陷的,那怎么办呢?
呵呵,如果真的有必要,完全再增加一个parent指针域来解决快速查找双亲的问题,这里就不细谈了。

其实这个表示法的最大好处是它把一颗复杂的树变成了一颗二叉树。
*/

 

你可能感兴趣的:(树的抽象数据类型和几种表示法)