二叉树专题-lintcode非递归遍历与总结
来源:互联网 发布:知君本无邪 编辑:程序博客网 时间:2024/06/07 00:18
紧接着上一篇文章讨论后序遍历的非递归写法,可以先看看上一篇文章:递归与非递归遍历
上一篇文章已经讨论到了:后序遍历要求最后访问根节点,访问完左子树后,要想进入右子树,无法直接跳入左子树,必须要有根的信息,从根节点才可进入右子树。但是栈中只保存了一次根的信息,出栈后获取了根,访问右子树,访问完了后便丢失了根的信息。这个特点导致了后序遍历的非递归写法比先序,中序复杂。
我们有了将节点入栈2次的想法。第一次出栈,只是作为一个中间量,为了通过这个量进入到右子树,第二次出栈,访问,便实现了后序的要求。当然,若一个节点没有右子树,只入栈一次,访问完左子树后,直接访问根就好了。
很快有了个最直接的解决方法:直接在结构体中添加一个flag,用来标志是否为第一次访问,很容易按照这个思路实现。但一些在线编程平台不允许修改结构体,那么我们可以定义一个q,表示上一次访问的节点。只有跟的右子树恰好为p时,表示左右子树访问完了,就可以访问根了。否则,需要再次入栈。
下面给出代码,并用例子说一些细节问题
void getResult(vector<int>& result,TreeNode * root){ /*递归版本 if(!root) return; getResult(result,root->left); getResult(result,root->right); result.push_back(root->val); */ //非递归版 stack<TreeNode*> s; TreeNode* p=root; if(p==NULL) return; s.push(p);//入栈 p=p->left; while(!s.empty()){ //不断向左侧走 while(p!=NULL){ s.push(p); p=p->left; } //执行到这里时,表示已经走到了当前子树的最左侧,p为NULL TreeNode* q=NULL;//表示上一次访问的节点 while(!s.empty()){ p=s.top();//取栈顶元素 s.pop();//出栈 //按照左右根的顺序访问,若p的右子树为上一次访问的q,则p的左右 //均访问了,可以访问p了 if(p->right==q){ result.push_back(p->val); q=p;//更新上一次访问的节点 } else{//说明右子树还未访问,需要将p再次入栈,同时转向右 //去访问右子树 s.push(p); p=p->right; break;//这个break是关键 } } } }
只写了一部分执行的流程,与我们分析的是一致的,关键在于从左子树跳到右子树的那条break语句
我们由分析可以看出来:
要想后序遍历一棵二叉树,首先要指针不断向左侧走,并存取路径;上例中,访问完了b为根的子树,那么跳到c,要处理以c为根的子树,必然要从c开始不断向左走
故向右跳的时候需要一条break语句,来终止不停的出栈
最后,总结一下3种非递归遍历的异同(先序和中序的代码可以参考上一篇文章)
1.程序是否执行的判断条件
先序中序后序栈非空,p非空栈非空,p非空栈非空原因:根左右,左根右的访问顺序,p指针最后是访问右子树,最后p会指向最右侧的那个NULL,故栈为空,p不为空是仍然要执行,两者都空才结束
而对于后序遍历,最后访问的是最最上面的根,不需要对p的判断
2.递归遍历与非递归遍历的一致性
递归中,左根右,根左右,左右根,无论哪种访问顺序,最先都是向左子树递归,故非递归写法中首先也是指针不断向左侧走。我们只是用栈模拟了递归中的入栈出栈。
想明白了这些,感觉非递归的写法也不是很难的,都是一一对应的,根据递归的流程直接转换过来就好。
- 二叉树专题-lintcode非递归遍历与总结
- 二叉树专题-lintcode递归与非递归遍历
- 二叉树后续非递归遍历-lintcode
- [二叉树专题]:先序遍历二叉树的递归实现与非递归实现
- 二叉树 递归 与 非递归 遍历
- 递归与非递归二叉树遍历
- 二叉树递归与非递归遍历
- 二叉树递归与非递归遍历
- 二叉树递归与非递归遍历
- 二叉树递归与非递归遍历
- 二叉树递归与非递归遍历
- 遍历二叉树(递归与非递归)
- LintCode 二叉树的遍历 (非递归)
- lintcode-二叉树的前序遍历(非递归)-66
- lintcode-二叉树的中序遍历(非递归)-67
- Lintcode 二叉树后序遍历 非递归形式
- 二叉树非递归遍历总结
- 二叉树的非递归遍历总结
- LLE原理总结
- 阵变换:沿任意轴旋转及其推导
- Banner
- 1074. 宇宙无敌加法器(20)
- 解析php中$_REQUEST的用法
- 二叉树专题-lintcode非递归遍历与总结
- git rebase 用法简介
- pygdal-基础操作
- Linux基础
- 多功能噪音消除器支持多种场景模式
- The servlets named [] and [] are both mapped to the url-pattern [/] which is not permitted
- 如何下载Spring各大版本?
- Python Requests实例,查询成绩
- Oracle某用户下的某个表如何恢复到过去某个时刻