欢迎来到淘文阁 - 分享文档赚钱的网站! | 帮助中心 好文档才是您的得力助手!
淘文阁 - 分享文档赚钱的网站
全部分类
  • 研究报告>
  • 管理文献>
  • 标准材料>
  • 技术资料>
  • 教育专区>
  • 应用文书>
  • 生活休闲>
  • 考试试题>
  • pptx模板>
  • 工商注册>
  • 期刊短文>
  • 图片设计>
  • ImageVerifierCode 换一换

    递归非递归两种算法遍历二叉树(共12页).doc

    • 资源ID:14561163       资源大小:138.50KB        全文页数:12页
    • 资源格式: DOC        下载积分:20金币
    快捷下载 游客一键下载
    会员登录下载
    微信登录下载
    三方登录下载: 微信开放平台登录   QQ登录  
    二维码
    微信扫一扫登录
    下载资源需要20金币
    邮箱/手机:
    温馨提示:
    快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。
    如填写123,账号就是123,密码也是123。
    支付方式: 支付宝    微信支付   
    验证码:   换一换

     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    递归非递归两种算法遍历二叉树(共12页).doc

    精选优质文档-倾情为你奉上一、设计思想1. 用递归算法遍历 设计思想:主要是通过不同程序顺序,从而实现递归的顺序遍历 前序遍历:先判断节点是否为空,如果不为空,则输出。再判断左节点是否为空,如果不为空,则递归调用,直到遍历到最左边。接着再遍历最左边的右子树,如果此时右子树不为空,则递归遍历左子树的操作,直到遍历到叶子节点。如果右子树为空,则回溯上次的递归调用,重复输出和遍历右子树的操作。 中序遍历: 先遍历左节点是否为空,如果不为空,则递归调用,直到遍历到最左边或者叶子节点,然后输出,接着再遍历最左边的右子树,如果此时右子树不为空,则递归重复遍历左子树的操作,直到遍历到叶子节点。如果右子树为空,则回溯到上次递归调用,重复输出和遍历右子树的操作。 后序遍历:先判断左节点是否为空,如果不为空则一直递归直到遍历到最左边,然后遍历右节点,再接着遍历到左子树的最右边,直到遍历到叶子节点。此时输出,回溯到上次递归,继续执行后面的操作,重复,直到将整个树遍历完毕。 2. 用非递归算法遍历 设计思想:主要是通过栈的存取,判空,从而实现树的遍历 前序遍历:通过一个循环实现。先输出节点的数值,因为栈的特性,则需要先判断右子树是否为空,如果不为空,则将右子树压栈。然后判断左子树是否为空,如果不为空,则将左子树压栈。接着再将栈里面的子树弹出赋给给当前节点变量,重复上述操作,直到栈为空后退出循环。 中序遍历:通过循环实现。将树一直遍历到最左端,并将中间所经过的节点保存在栈中,当遍历到最左边的时候,则弹出栈里面的子树。输出数值,将当前节点赋值为当前节点的右子树,遍历右子树,即重复上述操作,直到当前节点为空,并且栈内元素为0。 后序遍历:通过循环和标记栈实现。将数一直遍历到最左端,并将中间的节点保存在树栈中,同时同步的添加一个标记栈。当遍历到最左边的时候,弹栈并赋值给当前栈,然后判断标记栈的数值,如果数值为0的话则代表当前树没有遍历过,遍历右子树。然后重复上面的操作,如果数值为1的话则代表此时数已经遍历过了,可以开始输出了,为了避免重复输出,将当前栈赋为空。重复循环操作,直到栈内没有元素,且当前节点为空(因为一直左的操作并没有将右子树压栈)。开始Root=nullYN输出数据Root.getLTree=nullRoot=Tree tRoot.getRTree=nullNYYN结束开始Root=Tree tRoot=nullRoot.getLTree=nullNN输出数据YRoot.getRTree=null结束YN开始Root=Tree tRoot=nullRoot.getLTree=nullRoot.getRTree=nullY输出数据结束YYYNNN二、算法流程图图1 递归算法-先序遍历 图2 递归算法-后序遍历图3 递归算法-中序遍历开始t.getRtree=nullTree t=rootoutputt = nullNYPusht.getLtree=nullPushNYN栈为空t=stack.pop()YN结束Y开始Tree t=root压栈t = nullNYt=current.getLtree()t=stack.Pop()outputt=current.getRltree()栈为空N结束Y图4 非递归算法-先序遍历图5 非递归算法-中序遍历开始Tree t=rootPusht = nullNYt=t.getLtree()标签栈压栈t=stack.pop()标签栈出栈赋值给标志位判断栈是否已经入栈过NYt=t.getRTree()标签栈压栈出栈并赋值tOutputCurrent=null树栈为空且当前节点为空N结束Y图6 非递归算法-后序遍历三、源代码#include<stdio.h> #include<stdlib.h> typedef char ElemType; /定义树结构 typedef struct tree ElemType data; struct tree * lchild; struct tree * rchild; unsigned int isOut; /专为后序遍历设置的,0为不需要被输出,1为需要被输出 TreeNode, *Tree; /定义栈结构 typedef struct stack Tree * base; Tree * top; int stacksize; SqStack; void InitStack( SqStack &s ); void Push( SqStack &s, Tree e ); void GetTop( SqStack s, Tree &e ); void Pop( SqStack &s, Tree &e ); int StackEmpty( SqStack s ); void CreateTree(Tree &t); void PreOrder(Tree t); void PreOrder1(Tree t); void InOrder(Tree t); void InOrder1(Tree t); void PostOrder(Tree t); void PostOrder1(Tree t); int main() Tree T; printf("n按先序序列输入结点序列,'*'代表空:"); CreateTree(T); printf("n 递归先序遍历的结果: "); PreOrder(T); printf("n非递归先序遍历的结果:"); PreOrder1(T); printf("n 递归中序遍历的结果: "); InOrder(T); printf("n非递归中序遍历的结果:"); InOrder1(T); printf("n 递归后序遍历的结果: "); PostOrder(T); printf("n非递归后序遍历的结果:"); PostOrder1(T); printf("n"); return 0; void InitStack( SqStack &s ) /初始化栈 s.base = (Tree *)malloc(100*sizeof(Tree); if ( !s.base ) printf("InitStack内存分配出错,程序将推出执行!n"); exit (-1); s.top = s.base; s.stacksize = 100; void Push (SqStack &s, Tree e ) /元素入栈 接收一个 stack 类型变量和一个 tree* 类型变量 if ( s.top - s.base >= s.stacksize ) s.base = (Tree *)realloc(s.base,(s.stacksize+20)*sizeof(Tree); if ( !s.base ) printf("Push内存分配出错,程序将退出执行n"); exit (-1); s.top = s.base + s.stacksize;/ s.stacksize += 20; e->isOut = 0; *s.top+ = e; void GetTop( SqStack s, Tree &e )/获得栈顶元素 e = *(s.top - 1); /s.top为 tree* 类型 void Pop( SqStack &s, Tree &e )/出栈 if ( s.top = s.base ) printf("栈为空n"); return ; e = *(-s.top); int StackEmpty( SqStack s )/判断栈是否为空 if ( s.top = s.base ) return 1; return 0; void CreateTree(Tree &t)/以先序序列建立树 char ch; scanf("%c",&ch); if ( ch = '*' )t = NULL; else t = (Tree)malloc(sizeof(TreeNode); if ( !t ) printf("分配内存出错!"); return ; t->data = ch; CreateTree(t->lchild); CreateTree(t->rchild); void PreOrder(Tree t) /递归先序遍历,遍历顺序:根、左、右 /先访问根节点,再先序遍历左子树,再先序遍历右子树 if ( t )/如果树 t 不为空树,才继续执行先序遍历 printf("%c ",t->data); PreOrder(t->lchild); PreOrder(t->rchild); void InOrder(Tree t) /递归中序遍历,遍历顺序:左、中、右/先中序遍历左子树,再访问根节点,再中序遍历右节点 if ( t ) /如果树 t 为空树,则停止向下遍历 InOrder(t->lchild);printf("%c ",t->data); InOrder(t->rchild); void PostOrder(Tree t) /递归后序遍历,遍历顺序:左、右、根 if ( t ) PostOrder(t->lchild); PostOrder(t->rchild); printf("%c ",t->data); void PreOrder1(Tree t)/非递归先序遍历 Tree p = t;/p为 tree* 类型变量 SqStack s; InitStack(s); while ( p | !StackEmpty(s) ) /当树的节点不为空 或 栈不为空执行循环 if ( p ) /当数的此节点不为空时,打印此节点值且将此节点入栈 printf("%c ",p->data); Push(s,p); p = p->lchild; else /否则父节点出栈,p指向父节点的右子树 Pop(s,p); p = p->rchild; void InOrder1(Tree t) /非递归中序遍历 Tree p = t; SqStack s; InitStack(s); while ( p | !StackEmpty(s) ) if ( p ) Push(s,p); p = p->lchild; else Pop(s,p); printf("%c ",p->data); p = p->rchild; void PostOrder1(Tree t) /非递归后序遍历,遍历顺序:左、右、根 t->isOut = 0;/初始值表示不输出 Tree p = t; SqStack s; InitStack(s); while ( p | !StackEmpty(s) ) /节点非空 或 栈非空执行循环 if ( p ) if ( p->isOut ) /左右子树都已输出,则该节点也输出 Pop(s,p); printf("%c ",p->data); if (!StackEmpty(s) GetTop(s,p);/得到该节点元素的父节点 else p = NULL; else if ( (p->lchild) && (p->lchild->isOut = 1) ) /如果存在左子树,并且左子树已经遍历完,则说明该节点已经入栈p->isOut = 1; p = p->rchild; else/否则入栈该节点的树,并且走向它的左子树 Push(s,p); p = p->lchild; else GetTop(s,p); if ( p->rchild ) p = p->rchild; else Pop(s,p); printf("%c ",p->data); p->isOut = 1; if (!StackEmpty(s) GetTop(s,p); if ( p->lchild = NULL ) p->isOut = 1;/右子树已输出,将父节点isOut置1 else p = NULL; 四、运行结果图7 遍历二叉树运行结果图五、遇到的问题及解决这部分我主要遇到了如下三个问题,其内容与解决方法如下所列: l 第一个问题:递归的使用,没有完全理解递归的含义 描述:递归的使用是每次都将上次调用的现场保留,直到本次的方法的完成才会返回上次的调用的现场,由于没有完全的了解,所以在调用的时候回忽略掉上次保存的现场。 解决:通过例子来解决分析,每次将递归调用的现场都记录下来,然后再进行下次递归,从而避免了忽略掉的现场,得到错误的思想。 l 第二个问题:非递归如何实现遍历 描述:对于非递归,我们不能像递归一样能保存中间的现场,而如果不能保存上次树则不能调用当前树的下下个左子树或者右子树,所以我们必须得想出一种新的方法去实现现场的保存。 解决:通过一个栈来保存中间的调用线程,由于while循环也有像递归一样的过程,所以只要我们将每次调用的当前树的保存下来,那么下次调用的时候直接将栈里面的树弹出即可访问上一次的保存的现场的树。 l 第三个问题:对于非递归后序的实现 描述:由于后续遍历又本身的特殊性,左子树,右子树,中间节点这样的一个顺序,如果分开保存左子树和右子树,那么在遍历右子树后会丢失掉上次现场保留的中间节点,如果要像中序遍历一样的方法保存的话,那么每次弹出后遍历右节点也会丢失上次现场保留的中间节点。 解决:通过一个标签的形式,在每次压栈的时候都给树标记下,由于都是先访问左子树,再访问右子树,也就是说每棵树都是访问两次。那么就可以通过判断树的标志而实现此时是否遍历左节点和右节点完成,从而输出中间节点。六、心得体会这次的实验相对来说不是很复杂,但是有些本质上的理论知识没有深入理解的话,那么简单的东西也会变得很复杂,所以说,越是简单的东西,包含的知识量越多。二叉树遍历的实验,让我进一步深刻理解了二叉树创建的原理,而不是将它当做书本上的一些定义和理论的东西,当然,通过这次实验,遍历二叉树的前序遍历、中序遍历、后序遍历的三种方法也有了进一步的巩固。当只有理论的东西有实践的价值的时候,理解起来会更加的透彻,同时我也重新复习了一遍递归的过程。就像这次,由于没有对递归有深刻的记忆,所以导致整个实验做起来很吃力,所以说,温故而知新,这个才是学习的的精髓,当一边学习新的知识,一边却忘记以往的理论原理,那么这样的理论基础也太脆弱了。这样建立起来的大厦也只是豆腐渣工程。总而言之,学习是一个不断获取和不断遗忘的过程,我们要做的是将这个天平始终保持在获取这边,这就是这次实验带给我最大的收获。专心-专注-专业

    注意事项

    本文(递归非递归两种算法遍历二叉树(共12页).doc)为本站会员(飞****2)主动上传,淘文阁 - 分享文档赚钱的网站仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知淘文阁 - 分享文档赚钱的网站(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    关于淘文阁 - 版权申诉 - 用户使用规则 - 积分规则 - 联系我们

    本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

    工信部备案号:黑ICP备15003705号 © 2020-2023 www.taowenge.com 淘文阁 

    收起
    展开