树存储结构

二叉树存储可以用顺序存储(转化为完全二叉树用数组存,结点孩子和双亲下标能互相快速定位),也可以用链表来存(主要为二叉链表,结点存有左右孩子指针)。

那么树能怎么存储呢?

双亲表示法

借鉴二叉树的顺序存储思路,用数组存储每个结点,不过此处双亲和孩子下标不再有相互关系,因此需要给结点增加数据成员 parent,记录双亲结点在数组的下标(根结点的parent = -1),如图:

此时 结点数据成员有 data + parent

// 结点成员有 data, parent
typedef struct
{
    /* data */
    ElemType data;  // 结点内容
    int parent;     // 双亲在数组的下标
}PTNode;

静态存储

#define MaxTreeNodes 100
typedef struct
{
    /* data */
    PTNode nodes[MaxTreeNodes];
    int n;     // 记录结点数
    int r;     // 记录根结点下标 (可有可无)
}PTree;

动态存储

// 动态存储
typedef struct
{
    /* data */
    PTNode *nodes;  // 初始化时动态分配空间
    int n;
    int r;
}PTree;

阿Q:该方法适用于频繁找双亲的场景(结点p找孩子 需要遍历数组,若当前结点的parent为p下标,则当前结点为p的孩子,找孩子比较麻烦)。


孩子表示法

怎样能将结点p的孩子串起来呢? p -> child1 -> child2 -> … ,用单链表即可。

然后再用数组将全部结点存储进去(数组存结点,结点链孩子),如图:

孩子数据成员有:index(该结点在数组的位置)+ next

结点数据成员有:data + next

// 孩子结点
typedef struct CNode
{
    /* data */
    int index;  // 结点在数组的位置
    struct CNode *next;
}CNode;
// 结点
typedef struct
{
    /* data */
    ElemType data;
    CNode *next;
}CTNode;

静态存储

// 整棵树
typedef struct
{
    /* data */
    CTNode nodes[MaxTreeNodes];
    int n;      // 记录结点数
    int r;      // 记录根结点的下标
}CTree;

动态存储

//动态存储
typedef struct
{
    /* data */
    CTNode *nodes;  // 初始化时动态分配空间
    int n;
    int r;
}CTree;

阿Q:该方法适用于频繁找孩子的场景(结点p找双亲,需要遍历数组,若当前结点的next,next->next一直到null中都没找到结点p,那么次结点不为p的双亲,否则该结点即为p的双亲,找双亲麻烦)。


双亲 + 孩子 表示法

双亲和孩子表示法各有缺点,将两者融合起来就互补短处了,如图:

那么只需要修改孩子表示法中 结点 结构,数组只需修改结构名即可

此时结点数据成员有 parent + data + next

// 孩子结点
typedef struct CNode
{
    /* data */
    int index;  // 结点在数组的位置
    struct CNode *next;
}CNode;

// 结点 (增加parent数据成员)
typedef struct
{
    /* data */
    int parent;  // 增加部分
    ElemType data;
    CNode *next;
}CPTNode;

// 整棵树(以静态存储为例)
typedef struct
{
    /* data */
    CPTNode nodes[MaxTreeNodes];
    int n;
    int r;
}CPTree;

阿Q:找孩子和找双亲都很方便(用空间换时间,阿Q比较推荐)


孩子兄弟表示法

在二叉树中,二叉链表的指针分别指向左右孩子。

但是在树结构中,如果链表全指向孩子,二叉链表肯定是不行的了。

但换个思路,如果将二叉链表的左指针指向第一个孩子,右指针指向兄弟,那就可行了啊(因此孩子兄弟表示法又称为二叉树表示法),如图:

阿Q:指针指向能改变整个结构(思维不能僵化)。

结点数据成员: firstchild + data + nextsibling

// 二叉树表示法
// 结点
typedef struct CSNode
{
    /* data */
    ElemType data;
    
    // 指向第一个孩子 
    struct CSNode *firstchild;

    // 指向兄弟
    struct CSNode *nextsibling;

}CSNode, *CSTree;

阿Q:方便实现转化为二叉树的操作,容易找结点的孩子(结点p的孩子,结点p的左指针指向第一个孩子,沿着右支走到 null,期间的所有结点均为p的孩子)。

二叉树和树的转换 即 通过此方式进行的,详情看树、森林、二叉树的转换


双亲 + 孩子兄弟表示法

和二叉树的二叉链表存储一样,用三叉链表实现,结点增加数据成员 指针parent 即可。

// 三叉链表示法
// 结点
typedef struct CSPNode
{
    /*data*/
    ElemType data;

    struct CSPNode *firstchild, *nextsibling;

    // 增加parent指针
    struct CSPNode *parent;

}CSPNode, *CSPTree;

评论

发送评论 编辑评论


上一篇
下一篇