- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
第6章节 树
第6章 树 在介绍常用的三种遍历算法之前,先介绍一下遍历的具体方法。例如有一棵二叉树,它有四个结点。为了便于理解遍历的思想,暂时为每个没有子树的结点均补充上相应的空子树,用?表示,见图6-3-1。 下面介绍三种遍历算法,在算法中将采用二叉链表作为二叉树的存储结构。 6.3.1.1 先根遍历 先根遍历的递归定义为: 若二叉树非空,则 (1)访问根结点; (2)按先根次序遍历左子树; (3)按先根次序遍历右子树。 否则,遍历结束。 算法6.2为先根遍历二叉树的递归算法,其中访问根结点的操作简化为输出根结点的值,输出格式具体使用时加上,在后面的各种有关算法同样处理。 算法6.2 void Preorder(BTNode *bt) { if (bt) { printf(bt-data); Preorder(bt-lchild); Preorder(bt-rchild); } } 为了进一步理解递归算法,现在结合图6-3-1中的二叉树,对算法6.2的执行情况进行分析,如图6-3-2所示。 对于先根遍历二叉树而言,在访问根结点之后,我们可以直接找到这个根的左子树进行遍历;但是当左子树遍历完毕之后,我们还必须沿着已经走过的路线返回到根结点,再通过根结点才能找到它的右子树。因此,在我们从根结点走向它的左孩子之前,必须把根结点的地址(指针)送入一个栈中暂存起来。在左子树遍历完毕之后,我们再按后进先出的原则取回栈顶元素,便得到了根结点的地址,最后遍历根的右子树。 根据上面的思想,容易写出下面的先根遍历二叉树的非递归算法。 算法6.3 void Preorder2(BTNode * bt) { p=bt ; top=0 ; while ( p || top) { if (p) { printf ( p -data); ++p ; s [ top ]=p; p=p- lchild; } else{ p=s[top]; - -top; p=p- rchild; } } } 对照图6-3-1中的二叉树,在先根非递归遍历过程中其栈S的内容变化如图6-3-3所示。 分析上面的算法。假定二叉树有n个结点,由于每个结点仅被访问一次,每个结点的指针要进一次栈,出一次栈,因此,算法中的输出语句、进栈和退栈的操作均被执行n次,算法的时间复杂度为O(n)。 算法中的栈所需要的最大容量与二叉树的深度直接有关。我们可以看出,栈中的元素(结点的指针)序列实际上是由二叉树的根结点到某个结点所经分枝上的结点(指针)所组成的,所以栈中元素的个数最多等于二叉树的深度。我们知道,有n个结点的二叉树的深度的最大值为n,因此栈所需要的最大容量M不超过n。 中序遍历算法的非递归描述 BiTNode *GoFarLeft(BiTree T; Stack *S) { if(!T) return NULL; while(T?lchild){ push(S,T); T=T?lchild;} return T; } 6.3.1.3 后根遍历 后根遍历的递归定义为:若二叉树非空,则 (1)按后根次序遍历左子树; (2)按后跟次序遍历右子树; (3)访问根结点。 否则,遍历结束。 显然,只要将访问根结点的操作移至遍历左子树、右子树的操作后即可得出后跟遍历递归算法
文档评论(0)