世界十大博彩公司排行--大品牌,值得信赖平凉的世界-世界的平凉!2016年最新最快的365bet体育在线赛事请关注本站!![网站地图]

二叉树的四种遍历算法

发布时间: 2020-07-05 02:55  |  来源: 原创  |  作者: admin
本文转自:简单地理解,满足以下两个条件的树就是二叉树:经过前人的总结,二叉树具有以下几个性质:性质 3 的计算方法为:对于一个二叉树来说,除了度为 0 的叶子结点和度为
本文转自: 简单地理解,满足以下两个条件的树就是二叉树: 经过前人的总结,二叉树具有以下几个性质: 性质 3 的计算方法为:对于一个二叉树来说,除了度为 0 的叶子结点和度为 2 的结点,剩下的就是度为 1 的结点(设为 n1),那么总结点 n=n0+n1+n2。 同时,对于每一个结点来说都是由其父结点分支表示的,假设树中分枝数为 B,那么总结点数 n=B+1。而分枝数是可以通过 n1 和 n2 表示的,即 B=n1+2n2。所以,n 用另外一种方式表示为 n=n1+2n2+1。 两种方式得到的 n 值组成一个方程组,就可以得出 n0=n2+1。 满二叉树 如果二叉树中除了叶子结点,每个结点的度都为 2,则此二叉树称为满二叉树。图1即为满二叉树。 下图是本节二叉树用例图1: 满二叉树除了满足普通二叉树的性质,还具有以下性质: 完全二叉树 如果二叉树中除去最后一层节点为满二叉树,且最后一层的结点依次从左到右分布,则此二叉树被称为完全二叉树。 如图 a) 所示是一棵完全二叉树,图 b) 由于最后一层的节点没有按照从左向右分布,因此只能算作是普通的二叉树。 完全二叉树除了具有普通二叉树的性质,它自身也具有一些独特的性质,比如说,n 个结点的完全二叉树的深度为 ?log2n?+1。 表示取小于 的最大整数。例如,=2,而 结果也是 2。 对于任意一个完全二叉树来说,如果将含有的结点按照层次从左到右依次标号(如图 3a)),对于任意一个结点 i ,完全二叉树还有以下几个结论成立: 二叉树的存储结构有两种,分别为顺序存储和链式存储。本节先介绍二叉树的顺序存储结构。 二叉树的顺序存储,指的是使用顺序表(数组)存储二叉树。需要注意的是,顺序存储只适用于完全二叉树。换句话说,只有完全二叉树才可以使用顺序表存储。因此,如果我们想顺序存储普通二叉树,需要提前将普通二叉树转化为完全二叉树。 有读者会说,满二叉树也可以使用顺序存储。要知道,满二叉树也是完全二叉树,因为它满足完全二叉树的所有特征。 普通二叉树转完全二叉树的方法很简单,只需给二叉树额外添加一些节点,将其"拼凑"成完全二叉树即可。如下图所示: 左侧是普通二叉树,右侧是转化后的完全(满)二叉树。解决了二叉树的转化问题,接下来学习如何顺序存储完全(满)二叉树。 完全二叉树的顺序存储,仅需从根节点开始,按照层次依次将树中节点存储到数组即可。 如上图所示,此为一棵普通的二叉树,若将其采用链式存储,则只需从树的根节点开始,将各个节点及其左右孩子使用链表存储即可。因此,上图对应的链式存储结构如下图所示: 由图可知,采用链式存储二叉树时,其节点结构由 3 部分构成(如下图所示): 链式存储结构对应的 C 语言代码为: 其实,二叉树的链式存储结构远不止上图所示的这一种。例如,在某些实际场景中,可能会做 “查找某节点的父节点” 的操作,这时可以在节点结构中再添加一个指针域,用于各个节点指向其父亲节点,如下图所示: 这样的链表结构,通常称为三叉链表。 利用上图所示的三叉链表,我们可以很轻松地找到各节点的父节点。因此,在解决实际问题时,用合适的链表结构存储二叉树,可以起到事半功倍的效果。 二叉树先序遍历的实现思想是: 以图 1 为例,采用先序遍历的思想遍历该二叉树的过程为: 因此,图 1 中二叉树采用先序遍历得到的序列为: 1 2 4 5 3 6 7 递归实现 二叉树的先序遍历采用的是递归的思想,因此可以递归实现,其 C 语言实现代码为: 非递归实现 而递归的底层实现依靠的是栈存储结构,因此,二叉树的先序遍历既可以直接采用递归思想实现,也可以使用栈的存储结构模拟递归的思想实现,其 C 语言实现代码为: 二叉树中序遍历的实现思想是: 以图 1 为例,采用中序遍历的思想遍历该二叉树的过程为: 因此,图 1 中二叉树采用中序遍历得到的序列为: 4 2 5 1 6 3 7 递归实现 二叉树的中序遍历采用的是递归的思想,因此可以递归实现,其 C 语言实现代码为: 非递归实现 而递归的底层实现依靠的是栈存储结构,因此,二叉树的先序遍历既可以直接采用递归思想实现,也可以使用栈的存储结构模拟递归的思想实现。 中序遍历的非递归方式实现思想是:从根结点开始,遍历左孩子同时压栈,当遍历结束,说明当前遍历的结点没有左孩子,从栈中取出来调用操作函数,然后访问该结点的右孩子,继续以上重复性的操作。 除此之外,还有另一种实现思想:中序遍历过程中,只需将每个结点的左子树压栈即可,右子树不需要压栈。当结点的左子树遍历完成后,只需要以栈顶结点的右孩子为根结点,继续循环遍历即可。 两种非递归方法实现二叉树中序遍历的代码实现为: 二叉树后序遍历的实现思想是:从根节点出发,依次遍历各节点的左右子树,直到当前节点左右子树遍历完成后,才访问该节点元素。 如图 1 中,对此二叉树进行后序遍历的操作过程为: 由此,对图 1 中二叉树进行后序遍历的结果为: 4 5 2 6 7 3 1 递归实现 后序遍历的递归实现代码为: 非递归实现 递归算法底层的实现使用的是栈存储结构,所以可以直接使用栈写出相应的非递归算法。 后序遍历是在遍历完当前结点的左右孩子之后,才调用操作函数,所以需要在操作结点进栈时,为每个结点配备一个标志位。当遍历该结点的左孩子时,设置当前结点的标志位为 0,进栈;当要遍历该结点的右孩子时,设置当前结点的标志位为 1,进栈。 这样,当遍历完成,该结点弹栈时,查看该结点的标志位的值:如果是 0,表示该结点的右孩子还没有遍历;反之如果是 1,说明该结点的左右孩子都遍历完成,可以调用操作函数。 完整实现代码为: 层次遍历方式:按照二叉树中的层次从左到右依次遍历每层中的结点。具体的实现思路是:通过使用队列的数据结构,从树的根结点开始,依次将其左孩子和右孩子入队。而后每次队列中一个结点出队,都将其左孩子和右孩子入队,直到树中所有结点都出队,出队结点的先后顺序就是层次遍历的最终结果。 层次遍历的实现过程 例如,层次遍历图 1 中的二叉树: 实现代码