树的孩子兄弟表示法实例(C++实现的)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树的孩子兄弟表示法实例(C++实现的)相关的知识,希望对你有一定的参考价值。

麻烦帮我写出来可以吗

孩子兄弟表示法
树的左儿子右兄弟表示法又称为二叉树表示法或二叉链表表示法。每个结点除了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;
参考技术A // 根据字符串型树建立树的孩子兄弟二叉链表存储结构T
void CSTreeCreate(CSTree &T)

LinkStack S;
StackInit(S);
CSTree p,q=T;
Sn=1;
char ch=Str[Sn];
while(ch && ch!=';')

if(isalnum(ch))

CSTreeInit(p);
p->data=ch;
if(Str[Sn-1]!=',') q->Child1=p;
else q->Sibling=p;

else if(ch=='(') StackPush(S,q);
else if(ch==')') StackPop(S,p);
++Sn;
ch=Str[Sn];
q=p;
//while
//CSTreeCreate

数据结构树---树的存储结构

前提

树中的某个结点的孩子可以有多个,所以仅仅使用简单的顺序结构或者链式结构是不能完全表示一整棵树的。
充分利用顺序存储结构和链式存储结构的特点,完全可以实现对树的存储结构的表示
我们表示一棵树的方法有:双亲表示法,孩子表示法,孩子兄弟表示法

补充

对于双亲表示法:我们先将双亲结点存入,我们每插入一个结点都是知道双亲结点位置的,数据可以直接插入。使用顺序存储结构更加方便
而对于孩子表示法,我们每次插入一个结点,对其子树的位置存放暂不确定,所有使用链式存储结构占主要

(一)双亲表示法

以双亲作为索引的关键词的一种存储方式
每个结点只有一个双亲,所以选择顺序存储占主要
以一组连续空间存储树的结点,同时在每个结点中,附设一个指示其双亲结点位置的指针域

1.结点结构 

技术分享图片

2.结点结构定义

/*树的双亲表示法结点结构定义*/
#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;    //r是根位置,n是结点数
}PTree;

 

技术分享图片

3.优缺点分析

优点:parent指针域指向数组下标,所以找双亲结点的时间复杂度为O(1),向上一直找到根节点也快
缺点:由上向下找就十分慢,若要找结点的孩子或者兄弟,要遍历整个树

4.改进一:方便获取孩子结点

在双亲结点基础上加入孩子结点位置,由于可能一个结点有多个子树,所以我们要根据数的度来设置添加几个孩子结点的元素

 

 技术分享图片

树的度为3,所以我们在结点结构设置上添加3个指针域,指向孩子结点,若是孩子为空则位置为-1
/*树的双亲表示法结点结构定义*/
#define MAX_TREE_SIZE 100

typedef int TElemType;

typedef struct PTNode    //结点结构
{
    TElemType data;    //结点数据
    int parent;        //双亲位置
    int child1;        //孩子结点1
    int child2;        //孩子结点2
    int child3;        //孩子结点3
}PTNode;

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

技术分享图片

缺点:这样消耗了大量的空间,是不必要的,

我们尽可能使用较小的空间,所以我们一般只添加一个长子域,可以获取到有0个或1个孩子结点,甚至两个子树都可以获取,但是对于较多的孩子我们若是非得使用顺序存储,就得使用上面方法。

注意:长子域是最左边孩子的域

/*树的双亲表示法结点结构定义*/
#define MAX_TREE_SIZE 100

typedef int TElemType;

typedef struct PTNode    //结点结构
{
    TElemType data;    //结点数据
    int parent;        //双亲位置
    int firstchild;    //长子域
}PTNode;

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

 

技术分享图片

5.改进二:方便获取各兄弟之间的关系

我们只需要增加一个有兄弟域,即可依次获取所有的兄弟结点
/*树的双亲表示法结点结构定义*/
#define MAX_TREE_SIZE 100

typedef int TElemType;

typedef struct PTNode    //结点结构
{
    TElemType data;    //结点数据
    int parent;        //双亲位置
    int rightsib;    //右兄弟结点
}PTNode;

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

 

技术分享图片

总结:

存储结构的设计是一个十分灵活的过程。一个存储结构设计是否合理,取决于基于该存储结构的运算是否合适,方便,时间复杂度好不好等。
例如若是我们既关注孩子又关注兄弟,而且对时间遍历要求高,那么我们可以扩展上面结构含有双亲域,长子域,右兄弟域

(二)孩子表示法(主要关注孩子结点)

由于每个结点可有多个子树(无法确定子树个数),可以考虑使用多重链表来实现。

技术分享图片

根据树的度来设置孩子域的个数,例如本例中度为3,设置3个孩子域
/*树的孩子表示法结点结构定义*/
#define MAX_TREE_SIZE 100

typedef int TElemType;

typedef struct PTNode    //结点结构
{
    TElemType data;    //结点数据
    int child1;    //孩子1结点
    int child2;    //孩子2结点
    int child3;    //孩子3结点
}PTNode;

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

技术分享图片

技术分享图片

 缺点:占用了大量不必要的孩子域空指针

改进一:为每个结点添加一个结点度域,方便控制指针域的个数

技术分享图片

技术分享图片

缺点:维护困难,不易实现

改进三:结合顺序结构和链式结构

技术分享图片

/*树的孩子表示法结点结构定义*/
#define MAX_TREE_SIZE 100

typedef int TElemType;

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;    //r是根位置,n是结点数
}CTree;

改进四:添加双亲域,方便查找双亲结点(双亲孩子表示法

技术分享图片

/*树的孩子表示法结点结构定义*/
#define MAX_TREE_SIZE 100

typedef int TElemType;

typedef struct CTNode    //孩子结点
{
    int child;
    struct CTNode* next;
}*ChildPtr;

typedef struct    //表头结构 
{
    TElemType data;
    int parent;
    ChildPtr firstChild;    //指向第一个孩子的指针
}CTBox;

typedef struct //树结构
{
    CTBox nodes[MAX_TREE_SIZE];    //结点数组
    int r, n;    //r是根位置,n是结点数
}CTree;

(三)孩子兄弟表示法

上面从双亲,孩子角度研究树的结构,下面我们从树的结点的兄弟角度来研究
任意一棵树,他的结点的第一个孩子如果存在就是唯一结点,他的右兄弟如果存在,也是唯一的,因此,我们设置两个指针,分别指向该结点的第一个孩子和该结点的右兄弟

技术分享图片

技术分享图片

typedef int TElemType;

typedef struct CSNode
{
    TElemType data;
    struct CSNode* firstchild, *rightsib;
}CSNode,*CSTree;
若有需要,可以再加入一个双亲域,但是上面的结构以及转换为二叉树,我们可以使用二叉树的一系列方法,来解决问题

 

以上是关于树的孩子兄弟表示法实例(C++实现的)的主要内容,如果未能解决你的问题,请参考以下文章

1 数据结构(13)_二叉树的概念及常用操作实现

C++ class实现孩子表示法

c++中树的拷贝构造函数的迭代实现

树的孩子兄弟表示法建树

[数据结构] 树森林的遍历

算法数据结构C++实现8 堆排序 难点分析