引言:
遍历二叉树:指按某条搜索路径巡访二叉树中每个结点,使得每个结点均被访问一次,而且仅被访问一次。
除了层次遍历外,二叉树有三个重要的遍历方法:先序遍历、中序遍历、后序遍历。
1、递归算法实现先序、中序、后序遍历:
(1)先序遍历:
void PreOrderTraverse(BiTree T)
{
if(T)
{
cout<<T->data;
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
}
(2)中序遍历:
void InOrderTraverse(BiTree T)
{ if(T)
{
InOrderTraverse(T->lchild);
cout<<T->data;
InOrderTraverse(T->rchild);
}
}
(3)后序遍历
void PostOrderTraverse(BiTree T)
{ if(T)
{ PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
cout<<T->data;
}
}
2.非递归算法实现先序、中序、后序遍历:
采用非递归算法则需要利用栈来实现对二叉树的遍历:
(1)先序遍历非递归算法
void PreOrder_non_recursion(BiTree T)//先序遍历的非递归算法
{
LinkStack S;
InitStack (S);
BiTree p,q;
p=T;
while(p||!StackEmpty(S))
{
if(p)
{
Push(S,*p);
cout<<p->data; //访问根节点
p=p->lchild; //遍历左子树
}
else
{
Pop(S,*q);
p=q->rchild; //遍历右子树
}
}
}
(2)中序遍历非递归算法
void InOrder_non_recursion(BiTree T)//中序遍历的非递归算法
{
LinkStack S;
InitStack (S);
BiTree p;
BiTree q;
p=T;
while(p||!StackEmpty(S))
{
if(p)
{
Push(S,*p);
p=p->lchild; //遍历左子树
}
else
{
Pop(S,*q);
cout<<q->data; //访问根节点
p=q->rchild; //遍历右子树
}
}
}
(3)后序遍历非递归算法
(采用非递归算法实现对二叉树的后序遍历,会稍微复杂一些,本算法借用了两个栈结构)
void PostOrder_non_recursion(BiTree T)//后序遍历的非递归算法
{
LinkStack l_S,r_S;
InitStack (l_S);
InitStack (r_S);
BiTree p,q;
p=T;
Push(l_S,*p);
while(!StackEmpty(l_S))
{
Pop(l_S, *q);
Push(r_S,*q);
if(q->lchild){
Push(l_S, *q->lchild);
}
if(q->rchild){
Push(l_S,*q->rchild);
}
}
while(!StackEmpty(r_S))
{
Pop(r_S,*q);
cout<<q->data;
}
}
3.完整代码
1、采用按照先序遍历的顺序建立二叉链表,用‘#’表示空树。如图所示:
2、先序遍历的递归与非递归算法的对比:
#include<iostream>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
using namespace std;
typedef char TElemType;
typedef int Status;
typedef struct BiTNode{ //二叉树的存储结构
TElemType data; // 数据域
struct BiTNode *lchild; //左孩子指针
struct BiTNode *rchild; //右孩子指针
}BiTNode, *BiTree;
typedef struct StackNode { //栈的存储结构
BiTNode data; //栈数据元素类型为树结点型
struct StackNode *next;
} StackNode, *LinkStack;
Status InitStack(LinkStack &S) { //栈初始化
S = NULL;
return OK;
}
Status Push(LinkStack &S, BiTNode e) { //入栈
LinkStack p;
p = new StackNode; //生成新结点
if (!p) {return OVERFLOW;}
p->data = e; //将新结点数据域置为e
p->next = S; //将新结点插入栈顶
S = p; //修改栈顶指针为p
return OK;
}
Status Pop(LinkStack &S, BiTNode &e) { //出栈
LinkStack p;
if (S == NULL)
return ERROR; //栈空
e = S->data; //将栈顶元素赋给e
p = S; //用p临时保存栈顶元素空间,以备释放
S = S->next; //修改栈顶指针
delete p; //释放原栈顶元素的空间
return OK;
}
bool StackEmpty(LinkStack S) { //判断是否空栈
if (!S)
return true;
return false;
}
void CreateBiTree_PreOrder(BiTree &T){ //以先序次序创建二叉树
char ch;
cin>>ch;
if(ch=='#')
T=NULL;
else{
T=new BiTNode; //生成根结点
T->data=ch; //根结点的数据域置为ch
CreateBiTree_PreOrder(T->lchild);//构造左子树
CreateBiTree_PreOrder(T->rchild); //构造右子树
}
}
void PreOrder(BiTree T){ //先序遍历的递归递归算法
if(T)
{
cout<<T->data;
PreOrder(T->lchild);
PreOrder(T->rchild);
}
}
void PreOrder_non_recursion(BiTree T)//先序遍历的非递归算法
{
LinkStack S;
InitStack (S);
BiTree p,q;
p=T;
while(p||!StackEmpty(S))
{
if(p)
{
Push(S,*p);
cout<<p->data; //访问根节点
p=p->lchild; //遍历左子树
}
else
{
Pop(S,*q);
p=q->rchild; //遍历右子树
}
}
}
int main() {
BiTree T;
cout<<"以先序次序创建二叉链表,以#表示空子树:"<<endl;
CreateBiTree_PreOrder(T);
cout<<"先序序列(递归算法):";
PreOrder(T);
cout<<"\n先序序列(非递归算法):";
PreOrder_non_recursion(T);
return 0;
}
实验结果:
3、中序遍历的递归与非递归算法的对比:
#include<iostream>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
using namespace std;
typedef char TElemType;
typedef int Status;
typedef struct BiTNode{ //二叉树的存储结构
TElemType data; // 数据域
struct BiTNode *lchild; //左孩子指针
struct BiTNode *rchild; //右孩子指针
}BiTNode, *BiTree;
typedef struct StackNode { //栈的存储结构
BiTNode data; //栈数据元素类型为树结点型
struct StackNode *next;
} StackNode, *LinkStack;
Status InitStack(LinkStack &S) { //栈初始化
S = NULL;
return OK;
}
Status Push(LinkStack &S, BiTNode e) { //入栈
LinkStack p;
p = new StackNode; //生成新结点
if (!p) {return OVERFLOW;}
p->data = e; //将新结点数据域置为e
p->next = S; //将新结点插入栈顶
S = p; //修改栈顶指针为p
return OK;
}
Status Pop(LinkStack &S, BiTNode &e) { //出栈
LinkStack p;
if (S == NULL)
return ERROR; //栈空
e = S->data; //将栈顶元素赋给e
p = S; //用p临时保存栈顶元素空间,以备释放
S = S->next; //修改栈顶指针
delete p; //释放原栈顶元素的空间
return OK;
}
bool StackEmpty(LinkStack S) { //判断是否空栈
if (!S)
return true;
return false;
}
void CreateBiTree_PreOrder(BiTree &T){ //以先序次序创建二叉树
char ch;
cin>>ch;
if(ch=='#')
T=NULL;
else{
T=new BiTNode; //生成根结点
T->data=ch; //根结点的数据域置为ch
CreateBiTree_PreOrder(T->lchild);//构造左子树
CreateBiTree_PreOrder(T->rchild); //构造右子树
}
}
void InOrder(BiTree T){ //中序遍历的递归递归算法
if(T)
{
InOrder(T->lchild);
cout<<T->data;
InOrder(T->rchild);
}
}
void InOrder_non_recursion(BiTree T)//中序遍历的非递归算法
{
LinkStack S;
InitStack (S);
BiTree p;
BiTree q;
p=T;
while(p||!StackEmpty(S))
{
if(p)
{
Push(S,*p);
p=p->lchild; //遍历左子树
}
else
{
Pop(S,*q);
cout<<q->data; //访问根节点
p=q->rchild; //遍历右子树
}
}
}
int main() {
BiTree T;
cout<<"以先序次序创建二叉链表,以#表示空子树:"<<endl;
CreateBiTree_PreOrder(T);
cout<<"中序序列(递归算法):";
InOrder(T);
cout<<"\n中序序列(非递归算法):";
InOrder_non_recursion(T);
return 0;
}
实验结果:
4、后序遍历的递归与非递归算法的对比:
#include<iostream>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
using namespace std;
typedef char TElemType;
typedef int Status;
typedef struct BiTNode{ //二叉树的存储结构
TElemType data; // 数据域
struct BiTNode *lchild; //左孩子指针
struct BiTNode *rchild; //右孩子指针
}BiTNode, *BiTree;
typedef struct StackNode { //栈的存储结构
BiTNode data; //栈数据元素类型为树结点型
struct StackNode *next;
} StackNode, *LinkStack;
Status InitStack(LinkStack &S) { //栈初始化
S = NULL;
return OK;
}
Status Push(LinkStack &S, BiTNode e) { //入栈
LinkStack p;
p = new StackNode; //生成新结点
if (!p) {return OVERFLOW;}
p->data = e; //将新结点数据域置为e
p->next = S; //将新结点插入栈顶
S = p; //修改栈顶指针为p
return OK;
}
Status Pop(LinkStack &S, BiTNode &e) { //出栈
LinkStack p;
if (S == NULL)
return ERROR; //栈空
e = S->data; //将栈顶元素赋给e
p = S; //用p临时保存栈顶元素空间,以备释放
S = S->next; //修改栈顶指针
delete p; //释放原栈顶元素的空间
return OK;
}
bool StackEmpty(LinkStack S) { //判断是否空栈
if (!S)
return true;
return false;
}
void CreateBiTree_PreOrder(BiTree &T){ //以先序次序创建二叉树
char ch;
cin>>ch;
if(ch=='#')
T=NULL;
else{
T=new BiTNode; //生成根结点
T->data=ch; //根结点的数据域置为ch
CreateBiTree_PreOrder(T->lchild);//构造左子树
CreateBiTree_PreOrder(T->rchild); //构造右子树
}
}
void PostOrder(BiTree T){ //后序遍历的递归递归算法
if(T)
{
PostOrder(T->lchild);
PostOrder(T->rchild);
cout<<T->data;
}
}
void PostOrder_non_recursion(BiTree T)//后序遍历的非递归算法
{
LinkStack l_S,r_S;
InitStack (l_S);
InitStack (r_S);
BiTree p,q;
p=T;
Push(l_S,*p);
while(!StackEmpty(l_S))
{
Pop(l_S, *q);
Push(r_S,*q);
if(q->lchild){
Push(l_S, *q->lchild);
}
if(q->rchild){
Push(l_S,*q->rchild);
}
}
while(!StackEmpty(r_S))
{
Pop(r_S,*q);
cout<<q->data;
}
}
int main() {
BiTree T;
cout<<"以先序次序创建二叉链表,以#表示空子树:"<<endl;
CreateBiTree_PreOrder(T);
cout<<"后序序列(递归算法):";
PostOrder(T);
cout<<"\n后序序列(非递归算法):";
PostOrder_non_recursion(T);
return 0;
}
实验结果:
4.结语
对于先序、中序和后序遍历,如果采用非递归算法,则需要借助栈来实现。对于二叉树而言,还有一种大家更为熟知的遍历方式,那就是层次遍历。实现对二叉树的层次遍历,则需要借助队列来实现。实现对二叉树的层次遍历,可以参考C实现二叉树的层次遍历
欢迎大家一起来交流~