数据结构(王道考研笔记)——树和森林

一、树的存储结构

树的存储方式有多种,既可采用顺序存储结构,又可采用链式存储结构,要求能唯一地反映树中各结点之间的逻辑关系,这里介绍3种常用的存储结构。

1、双亲表示法

这种存储方式采用一组连续空间来存储每个结点,同时在每个结点中增设一个伪指针,指示

其双亲结点在数组中的位置。(根结点下标为0 , 其伪指针域为-1)。

 

// 双亲表示法的存储结构

#define MAX_TREE_SIZE 100 //树中最多结点数 
typedef struct{ //树的结点定义
    ElemType data; //数据元素
    int parent;   //双亲位置域 
}PTNode;
typedef struct{ //树的类型定义
    PTNode nodes[MAX_TREE_SIZE]; //双亲表示
    int n;   //结点数
}PTree;

        该存储结构利用了每个结点(根结点除外)只有唯一双亲的性质,可以很快得到每个结点的双亲结点,但求结点的孩子时需要遍历整个结构。

        PS:在树的顺序存储结构中, 数组下标代表结点的编号,下标中所存的内容指示了结点之间的关系。而在二叉树的顺序存储结构中,数组下标既代表了结点的编号,又指示了二叉树中各结点之间的关系。当然,二叉树属于树,因此二叉树都可以用树的存储结构来存储, 但树却不都能用二叉树的存储结构来存储

2 、孩子表示法

        孩子表示法是将每个结点的孩子结点都用单链表链接起来形成一个线性结构,此时n个结点就有n个孩子链表(叶子结点的孩子链表为空表)。

        这种存储方式寻找子女的操作非常直接,而寻找双亲的操作则需要遍历n个结点中孩子链表指针域所指向的n个孩子链表

3 、孩子兄弟表示法

        孩子兄弟表示法又称二叉树表示法,即以二叉链表作为树的存储结构。孩子兄弟表示法使每个结点包括三部分内容:结点值、指向结点第一个孩子结点的指针,及指向结点下一个兄弟结点的指针(沿此域可以找到结点的所有兄弟结点 )。

image.png

 

// 孩子兄弟表示法的存储结构

typedef struct CSNode{ 
    ElemType data; //数据域 
    struct CSNode *firstchild,*nextsibling; //第——个孩子和右兄弟指针 
}CSNode,*CSTree; 

        这种存储表示法比较灵活,其最大的优点可以方便地实现树转换为二叉树的操作,易于查找结点的孩子等,但缺点是从当前结点查找其双亲结点比较麻烦。若为每个结点增设一个parent域指向其父结点,则查找结点的父结点也很方便。

二、树、森林与二叉树的转换

        由于二叉树和树都可以用二叉链表作为存储结构,因此以二叉链表作为媒介可以导出树与二叉树的一个对应关系,即给定一棵树,可以找到唯一的一棵二叉树与之对应。从物理结构上看,它们的二叉链表是相同的,只是解释不同而已。

        树转换为二叉树的规则每个结点左指针指向它的第一个孩子,右指针指向它在树中的相邻右兄弟,这个规则又称“左孩子右兄弟”。由于根结点没有兄弟,所以对应的二叉树没有右子树

        树转换成二叉树的画法:① 在兄弟结点之间加一连线;②对每个结点,只保留它与第一个孩子的连线,而与其他孩子的连线全部抹掉;③以树根为轴心,顺时针旋转 45°。

image.png

        将森林转换为二叉树的规则与树类似:先将森林中的每棵树转换为二叉树,由于任何一棵和树对应的二叉树的右子树必空,若把森林中第二棵树根视为第一棵树根的右兄弟,即将第二棵树对应的二叉树当作第一棵二叉树根的右子树,将第三棵树对应的二叉树当作第二棵二叉树根的右子树 …… 以此类推,就可以将森林转换为二叉树。

        森林转换成二叉树的画法:① 将森林中的每棵树转换为相应的二叉树;②每棵树的根也可以视为兄弟关系,在每棵树的根之间加一条连线;③以第一棵树根为轴心,顺时针旋转 45°。

        二叉树转换为森林的规则若二叉树非空,则二叉树的根及其左子树为第一棵树的二叉树形式,故将根的右链断开。二叉树根的右子树又可视为一个由除第一棵树外的森林转换后的二叉树,应用同样的方法,直到最后只剩一棵没有右子树的二叉树为止,最后再将每棵二叉树依次转换成 树,就得到了原森林。二叉树转换为树或森林是唯一的

image.png

森林F转二叉树B

若 F 中 n 个非终端结点,则转为二叉树B后 右指针为空的节点数是?

        n+1

【总结点数N,B有N+1个空指针,且n个结点有左指针、N-n个结点无左指针;那么剩下的空指针都是右指针:(N+1)-(N-n)= n+1】

三、树和森林的遍历

(一)、树的遍历

        树的遍历是指用某种方式访问树中的每个结点,且仅访问一次。主要有两种方式:

1、先根遍历。先访问根结点,再依次遍历根结点的每棵子树,遍历子树时仍遵循先根后子树的原则。其遍历序列与这棵树相应二叉树的先序序列相同。

2 、后根遍历。若树非空, 先依次遍历根结点的每棵子树,再访问根结点,遍历子树时仍遵循先子树后根的规则。其遍历序列与这棵树相应二叉树的中序序列相同

(二)、森林的遍历

按照森林和树相互递归的定义,可得到森林的两种遍历方法。

1 、先序遍历森林。若森林为非空,则按如下规则进行遍历:

  • 访问森林中第一棵树的根结点。
  • 先序遍历第一棵树中根结点的子树森林。
  • 先序遍历除去第一棵树之后剩余的树构成的森林。

2 、中序遍历森林(也可称后根遍历)。森林为非空时,按如下规则进行遍历:

  • 中序遍历森林中第一棵树的根结点的子树森林。
  • 访问第一棵树的根结点。
  • 中序遍历除去第一棵树之后剩余的树构成的森林。

上图 5.17的森林的先序遍历序列为 A B C D E F G H I , 中序遍历序列为 B C D A F E H I G 。

        当森林转换成二叉树时,其第一棵树的子树森林转换成左子树,剩余树的森林转换成右子树,可知森林的先序和中序遍历即为其对应二叉树的先序和中序遍历。

        树和森林的遍历与二叉树的遍历关系:

image.png

 四、应用

1、哈夫曼树

哈夫曼树(Huffman Tree)及哈夫曼编码(Huffman Coding)_哈夫曼树编码_SS上善的博客-CSDN博客哈夫曼树(Huffman Tree)又称最优二叉树,给定N个权值作为N个叶子结点,构造一棵二叉树,使该树的带权路径长度达到最小。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。哈夫曼编码(Huffman Coding),又称霍夫曼编码,是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种。该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般就叫做Huffman编码(有时也称为霍夫曼编码)。本文所有概念性描述及图示均来自王道考研数据结构。..._哈夫曼树编码https://blog.csdn.net/lranqi/article/details/126038757?spm=1001.2014.3001.5501

 2、并查集

并查集(树的应用、集合)_SS上善的博客-CSDN博客/集合元素数组(双亲指针数组)https://blog.csdn.net/lranqi/article/details/131788170

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SS上善

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值