zoukankan      html  css  js  c++  java
  • 11.树的抽象数据类型和几种表示法

    /*
    树(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指针域来解决快速查找双亲的问题,这里就不细谈了。
    
    其实这个表示法的最大好处是它把一颗复杂的树变成了一颗二叉树。
    */
  • 相关阅读:
    Hackerrank alien-flowers(数学公式)
    Hackerrank manasa-and-combinatorics(数学推导)
    Codeforces 314B(倍增)
    Codeforces Round #403(div 2)
    Mutual Training for Wannafly Union #6
    几道splay
    高数(A)下 第十章
    Bestcoder #92
    codevs1700 施工方案第二季
    poj2631
  • 原文地址:https://www.cnblogs.com/go-ahead-wsg/p/13226900.html
Copyright © 2011-2022 走看看