二叉树新建、前序、中序、后序遍历非递归写法
2015-07-01 22:10
387 查看
/************************************************************************/ /* 包括内容: 1、二叉树的建立 2、二叉树的遍历(先序、中序和后序的递归、非递归遍历) 3、二叉树的层次遍历 4、二叉树的深度 5、二叉树的重建 */ /************************************************************************/ #include <iostream> #include <stack> using namespace std; struct TreeNode { int val; TreeNode *lchild,*rchild; TreeNode(int x):val(x),lchild(NULL),rchild(NULL){}; }; //递归方式,为了建成树后的访问,使用引用 void treeCreate(TreeNode * &T) { char ch; cin>>ch; // # 表示此节点为空 if (ch=='#') { T=NULL; } else{ int i=ch-'0'; T=new TreeNode(i); treeCreate(T->lchild);//利用lchild和rchild将树连接起来 treeCreate(T->rchild); } } // 非递归方式,则要用到栈,但问题是什么时候进栈,什么时候出战??? //所以如果是用()方式输入,这样当遇到左括号的时候入栈,右括号出战,逗号表示是右子树 void treeCreateNoneR(TreeNode * &T) { char ch; int lev=0;//记录左右子树存在情况 stack<TreeNode *> sta; T=NULL;//将T先置为空,指向新产生的根指针,整棵树才能建立起来 TreeNode *t; while (cin>>ch) { if(ch=='#') continue; else if (ch=='(') { sta.push(t); lev=1;//存在左子树 continue; } else if (ch==')') { sta.pop(); continue; } else if (ch==',')//存在右子树 { lev=2; continue; } int i=ch-'0'; t=new TreeNode(i); if (T==NULL)//这里将树的根联系起来 { T=t; } else { if(lev==1&&!sta.empty()) { TreeNode *p=sta.top(); p->lchild=t; } else if(!sta.empty()) { TreeNode *p=sta.top(); p->rchild=t; } } } } //先序遍历递归 void PreorderTraverse(TreeNode *root) { TreeNode *t=root; if (t) { cout<<t->val; PreorderTraverse(t->lchild); PreorderTraverse(t->rchild); } } //非递归先序遍历,先访问根,再依次访问左右子树 void PreorderTraverseNoneR(TreeNode *root) { TreeNode *t=root; stack<TreeNode *>sta; sta.push(t); while (!sta.empty())//栈非空的情况下循环 { t=sta.top();//每次访问的是栈顶元素 cout<<t->val; if (t->lchild && t->rchild)//左右子树均存在,那么右子树先入栈,左子树先入栈先访问 { sta.pop(); sta.push(t->rchild); sta.push(t->lchild); } else if(t->lchild)//只有左子树,则左子树入栈 { sta.pop(); sta.push(t->lchild); } else if (t->rchild) { sta.pop(); sta.push(t->rchild); } else sta.pop();//叶子节点,则父节点也要出栈 } } a //中序遍历 void InorderTraverse(TreeNode* root) { TreeNode *t=root; if (t) { InorderTraverse(t->lchild);//先遍历左子树 cout<<t->val;//访问根节点 InorderTraverse(t->rchild);//再遍历右子树 } } //非递归仍然借用栈来做,但是注意最先输出的是最最左子树节点 void InorderTraverseNoR(TreeNode *root) { TreeNode *t=root; stack<TreeNode*>sta; sta.push(t); while(!sta.empty()) { t=sta.top(); //根节点的左子树被访问后,top又为根节点的时候,会再次被访问,如何解决? //栈需要pop,但是可能又pop多了,所以干脆让NULL也入栈 while (t && !sta.empty() ) { t=t->lchild; sta.push(t); } sta.pop(); if (!sta.empty())//进行访问 { t=sta.top(); sta.pop(); cout<<t->val; sta.push(t->rchild);//右子树入栈 } } } //后序非递归遍历,先左子树,后右子树,再根节点。 void PostOrderTraverse(TreeNode *root) { TreeNode *t=root; if (t) { PostOrderTraverse(t->lchild); PostOrderTraverse(t->rchild); cout<<t->val; } } /************************************************************************/ /* 后序遍历的难点在于:需要判断上次访问的节点是位于左子树,还是右子树。*/ /*若是位于左子树,则需跳过根节点,先进入右子树,再回头访问根节点; 若是位于右子树,则直接访问根节点。 */ /************************************************************************/ void PostOrderTraverseNoR(TreeNode *root) { TreeNode *t=root; TreeNode *lastVisit=NULL; stack<TreeNode*> sta; sta.push(t); //移到左子树 while (t) { sta.push(t); t=t->lchild; }//循环结束,t已经为空,且已经便利到左子树底端 while (!sta.empty()) { t=sta.top(); sta.pop(); //根节点可以被访问的前提是没有右子树,或者右子树已经被访问 if(t->rchild==NULL || t->rchild==lastVisit) { cout<<t->val; //修改最近被访问的节点 lastVisit=t; } else{ //根节点再次入栈 sta.push(t); //进入右子树,且可肯定右子树一定不为空 t=t->rchild; while (t) { sta.push(t); t=t->lchild; } } } } int main() { char ch; TreeNode *root; root=new TreeNode(-1); //treeCreate(root); treeCreateNoneR(root); PreorderTraverse(root); PreorderTraverseNoneR(root); cout<<endl<<"In Order"<<" "; InorderTraverse(root); cout<<endl<<"In order none Re"<<" "; InorderTraverseNoR(root); cout<<"next "<<endl; cout<<endl<<"Post order none Re"<<" "; PostOrderTraverse(root); PostOrderTraverseNoR(root); }
最后一部分借鉴:
http://www.2cto.com/kf/201407/314705.html,多谢~
附上结果截图
相关文章推荐
- 新的开始
- 替换空格
- Oracle基础(四)pl/sql
- [华为机试练习题]33.二叉搜索树
- 数据库隔离级别
- win7下装ubuntu双系统后无法进入win7的解决方法
- JAVA集合之——Comparable和Comparator
- _attribute_((packed))
- typedef函数指针用法
- 要靠自己
- Median of Two Sorted Arrays
- JavaScript权威指南_117_第15章_脚本化文档_15.2-选取文档元素-通过CSS选择器选取元素
- 如此——程序媛的一天
- Project Euler:Problem 53 Combinatoric selections
- 简单的底部菜单 类似微信订阅号里面的底部菜单
- PAT Advanced 1093. Count PAT's (25) 同 PAT Basic 1040
- 学习空间数据挖掘的总结
- ReactNavtive框架教程(2)
- 双击事件
- 戴尔服务器impi 设置