双亲表示法、孩子表示法、孩子兄弟表示法(二叉树表示法),森林和二叉树的转换

一、双亲表示法

实现:定义数组结构存放树的结点,每个结点含两个域:
数据域:存放结点本身数据信息。
双亲域:指示本结点的双亲结点在数组中的位置。

结点结构表示为:

data parent

data是数据域,parent是指针域
例如:
在这里插入图片描述
可表示为:
在这里插入图片描述
r=0,n=10.(根结点位置和结点个数)

这样的存储结构,根据结点parent指针很容易找到它的双亲结点,所用时间复杂度为O(1),直到parent为-1时,找到了树的根结点,但是我们要知道结点的孩子是什么,对不起,请遍历整个结构才行。

所以双亲表示法特点是:找双亲容易,找孩子难。

结点结构:

typedef struct PTNode{
	int data;
	int parent;//双亲位置域
}PTNode;

树结构定义:

#define MAX_TREE_SIZE 100
typedef struct{
	PTNode nodes[MAX_TREE_SIZE];
	int r,n;//根结点的位置和结点个数
}PTree;

我们可以把结点扩展来解决找孩子结点的问题,但存储结构的设计是一个非常灵活的过程。一个存储结构设计的是否合理,取决于基于该存储结构的运算是否适合、是否方便,时间复杂度好不好等等。

二、孩子表示法(孩子链表)

具体办法是:把每个结点的孩子结点排列起来,看成是一个线性表,以单链表作存储结构,则n个结点有n个孩子链表(叶子结点的孩子链表为空),然后n个头指针又组成一个线性表,采用顺序存储结构,存放进一个一维数组中,如图所示
在这里插入图片描述

为此,设计两种结点结构,一个是孩子链表的孩子结点:

child next

child是数据域,用来存储某个结点在表头数组中的下标,next为指针域,存储指向某结点的下一个孩子结点的指针。

另一个是表头数组的表头结点,也就是双亲结点:

data first child

其中,data是数据域,firstchild是头指针域,存储该结点的孩子链表的头指针。

孩子表示法的结构定义代码:

孩子结点结构


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

表头结构(双亲结构)

typedef struct		//表头结构
{		
	int data;
	ChildPtr firstchild;
}CTBox;//孩子链表

树结构:

#define MAX_TREE_SIZE 100
typedef syruct		//树结构
{
	CTBox nodes[MAX_TREE_SIZE];//结点数组
	int n,r;//结点数和根结点的位置
}CTree;

特点:找孩子易,找双亲难

这样的结构对于我们要查找某个结点的某个孩子,或者找某个结点的兄弟,只需要查找这个结点的孩子单链表即可。对于遍历整棵树也是很方便的,对头结点的数组循环即可。


但是,要找双亲结点却很麻烦,我们可以把双亲表示法和孩子表示法综合一下,称为双亲孩子表示法,算是孩子表示法的改进。

我们在表头结构中新增加一个成员即可,存储双亲下标。为了多存储双亲,操作方便,我们牺牲了空间。
在这里插入图片描述

三、孩子兄弟表示法(二叉树表示法、二叉链表表示法)

任意一棵树,它的结点的第一个孩子如果存在就是唯一的,它的右兄弟如果存在也是唯一的。因此,我们用二叉链表作树的存储结构,链表中每个结点的两个指针域分别指向第一个孩子结点此结点的下一个兄弟结点
,根结点没有兄弟,置为空。
结点结构如表:


画的有些丑,将就着看哈~(最右边是nextsibling,写错了)

//树的孩子兄弟表示法结构定义
typedef struct CSNode 
{
	int data;
	struct CSNode *firstchild,*nextsibling;
}CSNode,*CSTree;//结点类型和指向结点类型的指针,指针表示孩子兄弟表示的二叉链表结构

举例:
在这里插入图片描述

这种表示法,给查找某个结点的某个孩子带来方便,当然想找到结点的双亲,这个表示法也是有缺陷的,所以真的有必要的话,完全可以再增加一个parent指针域来解决快速查找双亲的问题,大家试试吧

此表示法的最大好处就是把一棵复杂度的树变成了一颗二叉树。


四、森林(树)和二叉树的转换

1)将树转化为二叉树进行处理,利用二叉树的算法来实现对树的操作
2)由于树和二叉树都可以用二叉链表作存储结构,则以二叉链表作媒介可以导出树与二叉树之间的一个对应关系。

  1. 将森林转换成二叉树
    1)加线:在兄弟之间加一连线
    2)抹线:对每个结点,除了其左孩子外,去除其与其余孩子之间的关系
    3)旋转:以树的根结点为轴心,将整数顺时针转45度。
    记忆口诀:兄弟相连留长子
    过程如下:加线->抹线->旋转
    在这里插入图片描述

  2. 将二叉树转换为森林
    步骤:
    1)加线:若p结点是双亲结点的左孩子,则将p的右孩子,右孩子的右孩子… …沿着分支找到所有的右孩子,都与p的双亲用线连起来
    2)抹线:抹掉原二叉树中双亲与右孩子之间的连线
    3)调整:将结点按层次排列,形成树结构

记忆口诀:左孩右右连双线,去掉原来右孩线
过程如下:加线->抹线->调整(旋转)
在这里插入图片描述


内容参考:
《数据结构》严蔚敏

发布了34 篇原创文章 · 获赞 85 · 访问量 4608

猜你喜欢

转载自blog.csdn.net/weixin_45895026/article/details/104067660