C++编程练习(17)----“二叉树非递归遍历的实现“
二叉树的非递归遍历
最近看书上说道要掌握二叉树遍历的6种编写方式,之前只用递归方式编写过,这次就用非递归方式编写试一试。
C++编程练习(8)----“二叉树的建立以及二叉树的三种遍历方式“(前序遍历、中序遍历、后续遍历)
递归的思想也就是栈的思想,既然不用递归,那就改用栈的方式。
“递归=栈”
1、前序遍历
前序遍历按照“根结点-左孩子-右孩子”的顺序进行访问。
a)递归实现前序遍历:
void PreOrderTraverse(BiTNode *T) /*递归前序遍历*/
{
if (T==NULL)
return;
std::cout<<T->data<<"\t";
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
b)非递归实现前序遍历:
对于根结点P:
1)访问结点P,并将结点P入栈;
2)判断结点P的左孩子是否为空,若为空,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前的结点P,循环至1);若不为空,则将P的左孩子置为当前的结点P;
3)直到P为NULL并且栈为空,则遍历结束。
void nPreOrderTraverse(BiTNode *T) /*非递归前序遍历*/
{
if (T==NULL)
return;
BiTNode *p;
p = T;
std::stack<BiTNode*> stk;
while(p!=NULL||!stk.empty())
{
while(p!=NULL)
{
std::cout<<p->data<<"\t";
stk.push(p);
p = p->lchild;
}
if(!stk.empty())
{
p = stk.top();
stk.pop();
p = p->rchild;
}
}
}
2、中序遍历
中序遍历按照“左孩子-根结点-右孩子”的顺序进行访问。
a)递归实现中序遍历
void InOrderTraverse(BiTNode *T) /*递归中序遍历*/
{
if (T==NULL)
return;
InOrderTraverse(T->lchild);
std::cout<<T->data<<"\t";
InOrderTraverse(T->rchild);
}
b)非递归实现中序遍历
对于根结点P:
1)若其左孩子不为空,则将P入栈并将P的左孩子置为当前的P,然后对当前结点P再进行相同的处理;
2)若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的P置为栈顶结点的右孩子;
3)直到P为NULL并且栈为空则遍历结束。
void nInOrderTraverse(BiTNode *T) /*非递归中序遍历*/
{
if(T==NULL)
return;
std::stack<BiTNode*> stk;
BiTNode* p;
p = T;
while(p!=NULL || !stk.empty())
{
while(p!=NULL)
{
stk.push(p);
p = p->lchild;
}
if(!stk.empty())
{
p = stk.top();
stk.pop();
std::cout<<p->data<<"\t";
p = p->rchild;
}
}
}
3、后序遍历
后序遍历按照“左孩子-右孩子-根结点”的顺序进行访问。
a)递归实现后序遍历
void PostOrderTraverse(BiTNode *T) /*递归后序遍历*/
{
if(T==NULL)
return;
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
std::cout<<T->data<<"\t";
}
b)非递归实现后序遍历
要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。如果P不存在左孩子和右孩子,则可以直接访问它;或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。
对于根结点P:
1)将P入栈,设置当前结点 cur ;
2)将当前的 cur 置为栈顶结点,如果 cur 不存在左孩子和右孩子,或者 cur 存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则可以直接访问该结点并进行出栈操作。否则将 cur 的右孩子和左孩子依次入栈;
3)直到栈为空则遍历结束。
void nPostOrderTraverse(BiTNode *T) /*非递归后序遍历*/
{
if(T==NULL)
return;
BiTNode* cur; /*当前结点*/
BiTNode* pre = NULL; /*前一次输出的结点*/
std::stack<BiTNode*> stk;
stk.push(T);
while(!stk.empty())
{
cur = stk.top();
if((cur->lchild==NULL && cur->rchild==NULL) ||
(pre!=NULL && (cur->lchild==pre || cur->rchild==pre)))
{ /*如果当前结点没有孩子结点或者孩子节点都已被访问过*/
std::cout<<cur->data<<"\t";
stk.pop();
pre = cur;
}
else
{
if(cur->rchild!=NULL)
stk.push(cur->rchild);
if(cur->lchild!=NULL)
stk.push(cur->lchild);
}
}
}
4、完整测试代码
1)BiTree.h头文件
/* BiTree.h头文件 */
#include<iostream>
#include<stack>
typedef char TElemType; class BiTNode{ /*创建结点类,使用的是左右孩子表示法*/
public:
BiTNode():data(0),lchild(NULL),rchild(NULL){}
TElemType data;
BiTNode *lchild,*rchild;
}; void CreateBiTree(BiTNode **T) /*二叉树的建立,这里形参用的是双指针,需要注意*/
{ /*这里输入的是一个扩展二叉树,每个结点若有空指针,*/
TElemType ch; /*则将其值设为一个特定值,本代码中是'#'*/
std::cin>>ch;
std::cin.clear();
if(ch=='#')
*T=NULL;
else
{
*T=new BiTNode;
if(!*T)
exit(1);
(*T)->data=ch;
CreateBiTree(&(*T)->lchild);
CreateBiTree(&(*T)->rchild);
}
} void PreOrderTraverse(BiTNode *T) /*递归前序遍历*/
{
if (T==NULL)
return;
std::cout<<T->data<<"\t";
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
} void nPreOrderTraverse(BiTNode *T) /*非递归前序遍历*/
{
if (T==NULL)
return;
BiTNode *p;
p = T;
std::stack<BiTNode*> stk;
while(p!=NULL||!stk.empty())
{
while(p!=NULL)
{
std::cout<<p->data<<"\t";
stk.push(p);
p = p->lchild;
}
if(!stk.empty())
{
p = stk.top();
stk.pop();
p = p->rchild;
}
}
} void InOrderTraverse(BiTNode *T) /*递归中序遍历*/
{
if (T==NULL)
return;
InOrderTraverse(T->lchild);
std::cout<<T->data<<"\t";
InOrderTraverse(T->rchild);
} void nInOrderTraverse(BiTNode *T) /*非递归中序遍历*/
{
if(T==NULL)
return;
std::stack<BiTNode*> stk;
BiTNode* p;
p = T;
while(p!=NULL || !stk.empty())
{
while(p!=NULL)
{
stk.push(p);
p = p->lchild;
}
if(!stk.empty())
{
p = stk.top();
stk.pop();
std::cout<<p->data<<"\t";
p = p->rchild;
}
}
} void PostOrderTraverse(BiTNode *T) /*递归后序遍历*/
{
if(T==NULL)
return;
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
std::cout<<T->data<<"\t";
} void nPostOrderTraverse(BiTNode *T) /*非递归后序遍历*/
{
if(T==NULL)
return;
BiTNode* cur; /*当前结点*/
BiTNode* pre = NULL; /*前一次输出的结点*/
std::stack<BiTNode*> stk;
stk.push(T);
while(!stk.empty())
{
cur = stk.top();
if((cur->lchild==NULL && cur->rchild==NULL) ||
(pre!=NULL && (cur->lchild==pre || cur->rchild==pre)))
{ /*如果当前结点没有孩子结点或者孩子节点都已被访问过*/
std::cout<<cur->data<<"\t";
stk.pop();
pre = cur;
}
else
{
if(cur->rchild!=NULL)
stk.push(cur->rchild);
if(cur->lchild!=NULL)
stk.push(cur->lchild);
}
}
}
2)main文件
#include"BiTree.h"
using namespace std;
int main()
{
BiTNode *T=new BiTNode;
std::cout<<"请前序遍历输入各节点:";
CreateBiTree(&T);
cout<<"\n该树的前序遍历输出为:"<<endl;
PreOrderTraverse(T);
cout<<endl;
nPreOrderTraverse(T);
cout<<"\n该树的中序遍历输出为:"<<endl;
InOrderTraverse(T);
cout<<endl;
nInOrderTraverse(T);
cout<<"\n该树的后序遍历输出为:"<<endl;
PostOrderTraverse(T);
cout<<endl;
nPostOrderTraverse(T);
cout<<endl;
return 0;
}
5、测试结果
C++编程练习(17)----“二叉树非递归遍历的实现“的更多相关文章
- 数据结构之二叉树篇卷三 -- 二叉树非递归遍历(With Java)
Nonrecursive Traversal of Binary Tree First I wanna talk about why we should <code>Stack</c ...
- 数据结构二叉树的递归与非递归遍历之java,javascript,php实现可编译(1)java
前一段时间,学习数据结构的各种算法,概念不难理解,只是被C++的指针给弄的犯糊涂,于是用java,web,javascript,分别去实现数据结构的各种算法. 二叉树的遍历,本分享只是以二叉树中的先序 ...
- ZT 二叉树的非递归遍历
ZT 二叉树的非递归遍历 二叉树的非递归遍历 二叉树是一种非常重要的数据结构,很多其它数据结构都是基于二叉树的基础演变而来的.对于二叉树,有前序.中序以及后序三种遍历方法.因为树的定义本身就 是递归定 ...
- 二叉树3种递归和非递归遍历(Java)
import java.util.Stack; //二叉树3种递归和非递归遍历(Java) public class Traverse { /******************一二进制树的定义*** ...
- c/c++二叉树的创建与遍历(非递归遍历左右中,破坏树结构)
二叉树的创建与遍历(非递归遍历左右中,破坏树结构) 创建 二叉树的递归3种遍历方式: 1,先中心,再左树,再右树 2,先左树,再中心,再右树 3,先左树,再右树,再中心 二叉树的非递归4种遍历方式: ...
- JAVA递归、非递归遍历二叉树(转)
原文链接: JAVA递归.非递归遍历二叉树 import java.util.Stack; import java.util.HashMap; public class BinTree { priva ...
- 非递归遍历二叉树Java实现
2018-10-03 20:16:53 非递归遍历二叉树是使用堆栈来进行保存,个人推荐使用双while结构,完全按照遍历顺序来进行堆栈的操作,当然在前序和后序的遍历过程中还有其他的压栈流程. 一.Bi ...
- c语言描述的二叉树的基本操作(层序遍历,递归,非递归遍历)
#include<stdio.h> #include<stdlib.h> #define OK 1 #define ERROR 0 #define TRUE 1 #define ...
- 非递归遍历二叉树Java版的实现代码(没写层次遍历)
直接上代码呵呵,里面有注解 package www.com.leetcode.specificProblem; import java.util.ArrayList; import java.util ...
随机推荐
- spring加载过程中jar包加载不了,解决方法
当我们在开发spring项目时,一般会将jar包放到webInf/lib下,这样是myeclipse自动将jar包加载到tomcat中webapps下,但是当我们新建一个lib文件夹的情况下,我们ad ...
- kafka 集群部署 多机多broker模式
kafka 集群部署 多机多broker模式 环境IP : 172.16.1.35 zookeeper kafka 172.16.1.36 zookeeper kafka 172.16 ...
- svn + jenkins + maven 实现java环境的自动化构建和部署
1. 环境说明: 系统CentOS 7 x64 IP: 10.6.0.126 1.1 首先安装配置 svn Centos 7 通过yum 安装svn 既可, 版本为1.7.14 # yum -y ...
- man info --help区别
--help: 是一个工具选项,可以用来显示一些工具的信息 man : 可以显示系统手册页中的内容,这些内容大多数都是对命令的解释信息 PS: () Space 键可以显示下一屏的文本信息 () q ...
- [Unity Shader]Shader前述
什么是Shader Shader,也就是着色器,它的工作就是读取你的网格并渲染在屏幕上.Shader可以定义一些属性,你会用它来影响渲染模型时所显示的效果.当存储了这些属性的设置时,就是一个Mat ...
- HTML5 - Canvas动画样例(谷歌弹跳球)
1,样例说明 (1)在没有鼠标介入的情况下,这些球就像有磁性一样拼成"Google"字样. (2)在鼠标移动到其中后,小球像是受到了排斥,向画布的四周扩散,然后不规则地反弹回来. ...
- DownloadManager 版本更新,出现 No Activity found to handle Intent 的解决办法
项目中,进行版本更新的时候,用的是自己写的下载方案,最近看到了使用系统服务 DownloadManager 进行版本更新,自己也试试. 在下载完成以后,安装更新的时候,出现了一个 crash,抓取的 ...
- 微信小程序之----navigator页面跳转
navigator navigator跳转页面样式分为两种一种是左上角带返回按钮跳转到新的页面,另一种不带即在本页跳转,通过控制redirect属性 .js <view> <navi ...
- onethink微博插件雏形记
2014年7月30日 17:08:44 后台微博插件: 一.功能: 1.绑定微博 2.发布的文章自动发布到新浪微博 3.插件独立性强,修改地方少 二.效果: 插件目录 工程地址:http://down ...
- Linux之文件备份与恢复
文件备份与恢复 1.dump命令 dump命令用于备份ext2或者ext3文件系统.可将目录或整个文件系统备份至指定的设备,或备份成一个大文件. 语法 dump(选项)(参数) 选项 -0123456 ...