二叉树后序遍历的两种非递归实现思路
来源:互联网 发布:ios屏幕录像软件 编辑:程序博客网 时间:2024/06/15 05:49
后序遍历的非递归实现是三种遍历方式中最难的一种。因为在后序遍历中,要保证左孩子和右孩子都已被访问并且左孩子在右孩子前访问才能访问根结点,这就为流程的控制带来了难题。文章《二叉树的后序遍历(非递归算法)》中有另一种用两个栈实现后序遍历的非递归算法。下面介绍文章《二叉树的非递归遍历》中的另外两种思路。
第一种思路:对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,此时该结点出现在栈顶,但是此时不能将其出栈并访问,因此其右孩子还为被访问。所以接下来按照相同的规则对其右子树进行相同的处理,当访问完其右孩子时,该结点又出现在栈顶,此时可以将其出栈并访问。这样就保证了正确的访问顺序。可以看出,在这个过程中,每个结点都两次出现在栈顶,只有在第二次出现在栈顶时,才能访问它。因此需要多设置一个变量标识该结点是否是第一次出现在栈顶。
代码:
void PostOrder2(BinTree T){int flag[20];stack<BinTree> s;while(T){s.push(T);flag[s.size()] = 0; //0表示该结点第一次出现在栈顶 T = T->lChild;}while(!s.empty()){T = s.top();while(T->rChild && flag[s.size()] == 0){flag[s.size()] = 1;//1表示结点第二次出现在栈顶 T = T->rChild;while(T){s.push(T);flag[s.size()] = 0; T = T->lChild;}T = s.top();}//T = s.top();cout<<setw(3)<<T->data;s.pop();} }第二种思路:要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。如果P不存在左孩子和右孩子,则可以直接访问它;或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。
代码:
void PostOrder1(BinTree T){stack<BinTree> s; BinTree cur; //当前结点 BinTree pre=NULL; //前一次访问的结点 s.push(T); while(!s.empty()) { cur=s.top(); if((cur->lChild == NULL && cur->rChild == NULL) || (pre != NULL && (pre == cur->lChild || pre == cur->rChild))) { cout<<setw(3)<<cur->data; //如果当前结点没有孩子结点或者孩子节点都已被访问过 s.pop(); pre = cur; } else { if(cur->rChild!=NULL) s.push(cur->rChild); if(cur->lChild!=NULL) s.push(cur->lChild); } } }
测试程序:
#include <iostream>#include <stack>#include <queue>#include <vector>#include <iomanip>#include <string.h>using namespace std;typedef struct BinTreeNode{char data;BinTreeNode * lChild,*rChild;} BinTreeNode,*BinTree;void BuildBinTree(BinTree *pT){char item;cin>>item;if(item=='#'){*pT = NULL;}else {*pT = new BinTreeNode;(*pT)->data = item; BuildBinTree(&((*pT)->lChild));BuildBinTree(&((*pT)->rChild));}}void ClearBinTree(BinTree *pT){if(*pT){ClearBinTree(&((*pT)->lChild));ClearBinTree(&((*pT)->rChild));delete (*pT);*pT = NULL;}}void InOrder(BinTree T){if(T){cout<<setw(3)<<T->data;InOrder(T->lChild);InOrder(T->rChild);}}void PostOrder(BinTree T){if(T){PostOrder(T->lChild);PostOrder(T->rChild);cout<<setw(3)<<T->data;} }void PostOrder1(BinTree T){stack<BinTree> s; BinTree cur; //当前结点 BinTree pre=NULL; //前一次访问的结点 s.push(T); while(!s.empty()) { cur=s.top(); if((cur->lChild == NULL && cur->rChild == NULL) || (pre != NULL && (pre == cur->lChild || pre == cur->rChild))) { cout<<setw(3)<<cur->data; //如果当前结点没有孩子结点或者孩子节点都已被访问过 s.pop(); pre = cur; } else { if(cur->rChild!=NULL) s.push(cur->rChild); if(cur->lChild!=NULL) s.push(cur->lChild); } } } void PostOrder2(BinTree T){int flag[20];stack<BinTree> s;while(T){s.push(T);flag[s.size()] = 0; //0表示该结点第一次出现在栈顶 T = T->lChild;}while(!s.empty()){T = s.top();while(T->rChild && flag[s.size()] == 0){flag[s.size()] = 1;//1表示结点第二次出现在栈顶 T = T->rChild;while(T){s.push(T);flag[s.size()] = 0; T = T->lChild;}T = s.top();}T = s.top();cout<<setw(3)<<T->data;s.pop();} }int main(){BinTree T = NULL;BuildBinTree(&T);PostOrder(T);cout<<endl;PostOrder1(T);cout<<endl; PostOrder2(T);ClearBinTree(&T);}输入与输出:
输入:AB#D##CE##FGI###H##输出: D B E I G H F C A D B E I G H F C A D B E I G H F C A
REF:
1,http://www.cnblogs.com/dolphin0520/archive/2011/08/25/2153720.html
2,http://blog.csdn.net/cxllyg/article/details/7520037
0 0
- 二叉树后序遍历的两种非递归实现思路
- 二叉树后序遍历的非递归实现
- 二叉树的遍历 递归非递归 思路和 java实现
- 二叉树的遍历 递归非递归 思路和 java实现
- 二叉树的遍历 递归非递归 思路和 java实现
- 二叉树的遍历 递归非递归 思路和 java实现
- 非递归实现二叉树遍历(思路+代码)
- 二叉树三种遍历的非递归思路(JAVASCRIPT)
- 二叉树的递归遍历(思路简单清晰)
- 二叉树后序遍历的非递归实现方法
- 非递归实现二叉树的遍历
- 二叉树遍历的递归实现图解
- 二叉树的遍历递归实现
- 非递归实现二叉树的遍历
- 二叉树遍历的非递归实现
- 二叉树遍历的非递归实现
- 二叉树遍历的非递归实现
- 二叉树的创建遍历 递归实现
- C++ primer 第五版习题答案, Stanley B. Lippman( 斯坦利 李普曼)(持续更新中)
- 私户银行卡送礼洗钱出售
- vs2010字符串的转换
- Difference Between == and === : A Simple Comparison
- IOS开发笔记 术语篇
- 二叉树后序遍历的两种非递归实现思路
- pthread_cond_wait()使用、执行过程及一些问题
- IOS开发笔记 框架篇
- Dojo与jQuery综合比较分析
- sql server语句中日期时间格式化查询
- 反转带头结点的链表
- c#格式化日期
- ios8 新特性
- 傻瓜式教学:c++操作Excel