/* 树(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指针域来解决快速查找双亲的问题,这里就不细谈了。 其实这个表示法的最大好处是它把一颗复杂的树变成了一颗二叉树。 */