5.1 数的逻辑结构 5.1.1 1、树的定义 在树中常常将数据元素称为结点 (1)有且仅有一个特定的称为根的结点; (2)当n>1时,除根结点之外的其余结点被分成m(m>0)个互不相交的有限集合T1,T2,•••Tm,其中每个集合又是一棵树,并称为这个节点的子树。 2、树的基本术语: 结点的度、树的度 叶子节点、分支结点 孩子节点、分支结点、兄弟节点 路径、路径长度 祖先、子孙 结点的层数、树的深度(高度) 层序编号 有序树、无序树 森林 5.1.2 树的抽象数据类型定义 5.1.3树的遍历操作 1、前序遍历 树的前序遍历操作定义为: 若树为空,则空操作返回;否则 (1)访问根结点 (2)按照从左向右的顺序前序遍历根结点的每一棵子树。 2、中序遍历 树的中序遍历操作定义为: 若树为空,则空操作返回;否则 (1)按照从左向右的顺序后序遍历根结点的每一棵子树; (2)访问根结点。 3、层序遍历 树的层序遍历也称作树的广泛遍历,其操作定义为树的第一层开始,自上而下逐层遍历,在同一层中,按从左向右的顺序对结点逐个访问。 5.2树的存储结构 5.2.1 双亲表示法 由树的定义可知,树中每个结点都有且仅有一个双亲结点。所以利用这一特性,可以用一维数组来存储各个结点,数组中一个元素对应一个结点,数组元素包括树中结点的数据信息以及该结点的双亲在数组中的下标。 其中: Data为数据域,存储树中结点的数据信息; Parent为指针即游标,存储该结点的双亲在数组中的小标。 5.2.2孩子表示法 1、多重链表表示法 (1)指针域的个数等于该结点的度。 (2)指针域的个数等于树的度。 2、孩子链表表示法 把孩子看成一个线性表,且以单链表存储,称为该结点的孩子链表。则n个结点有n个孩子链表。 孩子节点有两类:孩子节点、表头结点。 5.2.3 双亲孩子表示法 即将双亲表示法和孩子链表表示法相结合的存储方法。仍将各结点的孩子分别组成单链表,同时用一维数组顺序存储树中的各结点,数组元素除了包括结点的数据信息和该结点的孩子链表的头指针之外,还增设一个域存储该结点的双亲在数组的下标。 5.2.4孩子兄弟表示法 又称二链表表示法,其方法是链表中每个结点除数据域外,还设置了两个指针分别指向该结点的第一个孩子和右兄弟链表的结构: Firstchild data rightsib 指针域,存储第一个孩子结点的存储地址 数据域,存储该结点的数据信息 指针域,存储该结点右兄弟结点的存储地址 5.3二叉树的逻辑结构 最简单的树结构,特别适合计算机处理,而且任何数都可以简单的转换为二叉树。(重点内容) 5.3.1二叉树的定义 二叉树是n(n>=0)个结点的有限集合,该集合或者为空集,或者有一个根节点和两棵互不相交的、分别称为根节点的左子树和右子树的二叉树组成。 二叉树具有五种基本形态: 1、空二叉树; 2、只有一个根结点; 3、根结点只有左子树; 4、根结点只有右子树; 5、根结点既有左子树又有右子树 特殊二叉树: 1、斜树; 2、满二叉树; 3、完全二叉树; 5.3.2二叉树的基本性质 性质5-1 二叉树的第i层上最多有2^(i-1)个结点(i>=1)。 性质5-2 在一棵深度为k的二叉树中,最多有2^k-1个结点,最少有k个结点。 性质5-3 在一棵二叉树中,如果叶子结点的个数为n0,度为2的结点个数为n2,则n0=n2+1. 性质5-4 具有n个结点的完全二叉树的深度为【log2^n】+1。 性质5-5 对一棵具有n个结点的完全二叉树中的结点从一开始按层序编号,则对于任意的编号为i(1<=i<=n)的结点,有: (1)如果i>1,则结点i的双亲的编号为【i/2】;否则结点i是根结点,无双亲。 (2)如果2i<=n,则 结点i的左孩子的编号为2i;否则结点i无左孩子。 (3)如果2i+1<=n,则结点i的右孩子的编号为2i+1,否则结点i无右孩子。 5.3.3 二叉树的抽象数据类型定义 同树类似,在不同的应用中,二叉树的基本操作不尽相同。 5.3.4 二叉树的遍历操作 二叉树的遍历是指从根节点出发,按照某种次序访问二叉树是所有结点,使得每个结点被访问一次且仅被访问一次。由于二叉树中每个结点都可能有两个子树,因此需要寻找一条合适的搜索路径。 1、前序遍历 前序遍历二叉树操作定义为: 若树为空,则空操作返回;否则 (1)访问根结点 (2)前序遍历根结点的左子树 (3)前序遍历根结点的右子树 2、中序遍历 中序遍历二叉树操作定义为: 若树为空,则空操作返回;否则 (1)中序遍历根结点的左子树 (2)访问根结点 (3)中序遍历根结点的右子树 3、后序遍历 后序遍历根结点的左子树 后序遍历根结点的右子树 访问根结点 4、层序遍历 二叉树的层序遍历是指从二叉树的第一层开始,从上之下逐层遍历,在同一层中,按从左到右的顺序对结点逐个访问。 5.4 二叉树存储结构及实现 5.4.1 顺序存储结构 具体步骤: (1)将二叉树按完全二叉树编号。 (2)将二叉树中的结点一编号顺序存储到一维数组中。 5.4.2 二叉链表 基本思想: 令二叉树的每个结点对应一个链表结点,链表结点除了存放于二叉树结点有关的数据信息外,还要设置指示左右孩子的指针。 5.4.3 三叉链表 在二叉链表存储方式下,从某个结点出发可以直接访问它的孩子结点,但要找到它的双亲结点,则需要从根节点开始搜索,最坏的情况下,需要遍历整个二叉链表。此时采用三叉树链表储存二叉树。 其中,data,lchild,rchild三个域的含义同二叉树,parent域为指向该结点的双亲结点指针。 5.4.4 线索链表 按照某种遍历次序对二叉树进行遍历,可以把二叉树中所有结点排成一个线性序列。在集体应用中,有时需要访问二叉树中的结点在某种遍历序列中前驱和后继,此时,在存储结构中应该保存结点在某种遍历序列中的前驱和后继信息。 前驱和后继结点的指针称为线索,加上线索的二叉树称为线索二叉树,加上线索的二叉链表称为线索链表。 5.5 二叉树遍历的非递归算法 5.5.1 前序遍历非递归算法 关键:在前序遍历过某个左子树后,如何找到该结点的右子树的根指针。 一般的前序遍历执行过程中,设要遍历二叉树的根指针为bt,可能出现两种情况: (1)若bt!=NULL,则表明当前二叉树不为空,此时,应输入根结点bt的值并将bt保存到栈中,准备继续遍历bt的左子树。 (2)若bt=NULL,则表明以bt为根指针的二叉树遍历完毕,并且bt是栈顶指针所指结点的左子树,若栈不空,则应根据栈顶指针所指结点找到待遍历右子树的根指针并赋予bt,以继续遍历下去;若栈空,则表明整个二叉树遍历完毕。 5.5.2 中序遍历非递归算法 此算法只是需要将前序遍历的非递归算法中输出的语句cout<<bt->data移到bt=s[top--]之后即可。 5.5.3 后序遍历非递归算法 后序遍历的不同在于:结点要出入两次栈,出两次栈,这种情况的含义和处理方法为: (1)第一次出栈:只遍历晚左子树,右子树尚未遍历,则该结点不出栈,利用栈顶结点找到它的右子树,准备遍历它的右子树。 (2)第二次出栈:遍历完右子树,该结点出栈,并访问它。 设根指针为bt,则可能有以下两种情况: (1)若bt!=NULL,则bt及标志flag入栈,遍历其左子树。 (2)若bt=NULL,此时栈空,则整个遍历结束;若栈不空,则表明栈顶结点的左子树或右子树已遍历结束。若栈顶点的标志flag=1,则表明栈结点的左子树已遍历完毕,将flag修改为2,修改为2,并遍历栈定点的右子树;若栈顶结点的标志flag=2,则表明栈结点的右子树也遍历完毕,输出栈顶结点。 5.6 树、森林与二叉树的转换 1.树转换为二叉树 将一棵树转换为二叉树的方法为: (1)加线——树中所有相邻的兄弟结点之间加一条线; (2)去线——对树中的每个节点,只保留它与第一个孩子结点之间的连线,删去它与其他孩子结点之间的连线。 (3)层次调节——以根结点为轴心,将树顺时针转动一定角度,使之层次分明。 2.森林转换成二叉树 (1)将森林中的每一棵二叉树转化成二叉树; (2)从第二课二叉树开始,依次把后一棵二叉树的根结点作为一棵二叉树根节点的右孩子,当所有二叉树连起来后,此时所得到的二叉树就是由森林转换得到的二叉树。 3、二叉树转换为树或森林 (1)加线——若某个结点x是其双亲y的左孩子,则把结点x的右孩子、右孩子的右孩子、……,都与结点y用线连起来; (2)去线——删去原二叉树中所有的双亲结点与右孩子结点的连线; (3)层次调整——整理由(1)、(2)两步所得到的树或森林,使之层次分明。 (4)森林的遍历 两种遍历方法;前序遍历后续遍历。 5.7 应用举例 5.7.1 二叉树的应用举例——哈夫曼及哈夫曼编码 1、哈夫曼树也称最优二叉树,在实际中有着广泛的应用。 叶子节点的权值 是对叶子结点赋予的一个有意义的数值量。 二叉树的带权路径长度 设二叉树具有n个带权值的叶子节点,从根节点到叶子节点的路径长度与相应的叶子节点权值的乘积之和叫做二叉树的带权路径长度,记为: WPL=EWkLk 哈夫曼树 给定一组具有确定权值的叶子结点,可以构造出不同的二叉树,将其中带权值路径长度最小的二叉树称为哈夫曼树。 哈夫曼算法基本思想: (1)初始化:由给定的n个权值构造n棵只有一个根结点的二叉树,从而得到一个二叉树集合。 (2)选取与合并:在F中选取根结点的权值最小的两棵二叉树分别作为左、右子树构造一棵新的二叉树,这棵新的二叉树的根结点的权值为其左右子树根结点的权值之和。 (3)删除与加入:在F中删除作为左、右子树的两棵二叉树,并将新建的二叉树加入到F中。 (4)重复(2)(3)两步的操作,当集合F只剩下一棵二叉树时这棵二叉树便是哈夫曼树。 2、哈夫曼编码 在进行程序设计时,通常给每一个字符记一个单独的代码来表示一组字符,我们称之为编码。 本章主要介绍了树与二叉树的相关概念和操作,这是数据结构中非常重要的部分,它们在计算机科学中有着广泛的应用,例如文件系统、编译器设计和数据压缩等。 5.1 树的逻辑结构 树是一种非线性的数据结构,由结点和边构成。每个结点包含数据信息,且只有一个根结点,其他结点分为多个子树。基本术语包括结点的度(结点拥有的子树数量)、叶子节点(没有子树的结点)、分支结点(有子树的结点)、孩子节点(父结点的子结点)、兄弟节点(拥有相同父结点的结点)、路径、路径长度、祖先、子孙、结点的层数和树的深度。 5.1.3 树的遍历操作 遍历是访问树中所有结点的过程,常见的遍历方法有前序遍历(根-左-右)、中序遍历(左-根-右)和层序遍历(从上到下逐层遍历)。 5.2 树的存储结构 为了在计算机内存中表示树,提出了几种不同的存储方法: - 双亲表示法:使用一维数组,每个元素包含数据信息和双亲结点的数组下标。 - 孩子表示法:包括多重链表表示法和孩子链表表示法,前者指针域数量等于结点度,后者以链表形式存储孩子结点。 - 双亲孩子表示法:结合双亲表示法和孩子链表表示法,同时存储双亲下标和孩子链表头指针。 - 孩子兄弟表示法:每个结点有两个指针,分别指向第一个孩子和右兄弟,也称为二链表表示法。 5.3 二叉树的逻辑结构 二叉树是树结构的特例,每个结点最多有两个子结点,分为左子树和右子树。二叉树有五种基本形态,包括空二叉树、只有一个根结点的二叉树等。二叉树还有特殊类型如斜树、满二叉树和完全二叉树。 5.3.2 二叉树的基本性质 二叉树的性质涉及到结点数量与深度的关系,例如第i层最多有2^(i-1)个结点,完全二叉树的性质等。 5.3.4 二叉树的遍历操作 二叉树的遍历与树的遍历类似,但因为二叉树的结点最多有两个子结点,所以遍历顺序有所不同,包括前序遍历(根-左-右)、中序遍历(左-根-右)和后序遍历(左-右-根)。 5.4 二叉树存储结构及实现 二叉树的存储结构有顺序存储(如完全二叉树的数组表示)和链式存储(如二叉链表、三叉链表和线索链表),这些结构便于实现遍历操作。 5.5 二叉树遍历的非递归算法 非递归遍历通常通过栈来实现,例如前序遍历和中序遍历可以通过维护一个栈来跟踪访问状态,后序遍历则需要更复杂的机制,结点可能需要进出栈两次。 5.6 树、森林与二叉树的转换 树、森林与二叉树之间可以相互转换,转换方法包括添加和移除连接线、层次调整等。 5.7 应用举例 二叉树的应用中,哈夫曼树(最优二叉树)和哈夫曼编码是典型例子。哈夫曼树通过构造最小带权路径长度的二叉树,常用于数据压缩;哈夫曼编码则为每个字符分配短码,提高编码效率。 总结来说,本章详细讲解了树和二叉树的定义、遍历、存储结构以及它们在实际问题中的应用,这些知识是理解和设计高效算法的基础。
- 粉丝: 5
- 资源: 2
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助