数据结构----二叉树的遍历
一.实验要求
二叉树的遍历操作是树形结构其他众多操作的基础。本实验旨在使学生进一步加深对二叉树的先序、中序和后序等三种遍历次序特点的理解,熟悉二叉链表存储结构,熟练掌握二叉树上的递归算法的设计技术。
二.实验题目
构造一棵二叉树,使用二叉链表方式存储,试设计程序,按照先序、中序、后序三种方式将这棵二叉树遍历出来,要求使用递归和非递归两种实现方式。
三.实现提示
1.二叉树的线性链表存储数据结构:
[cpp]
typedef char elemtype;
typedef struct bitree{
elemtype data;
struct bitree *lchild,*rchild;
}BiTree;
2.二叉树的构造方式(参考):
[cpp]
BiTree *create()
{
BiTree *q[100]; //定义q数组作为队列存放二叉链表中结点,100为最//大容量
BiTree *s; //二叉链表中的结点
BiTree *root ; //二叉链表的根指针
int front=1,rear=0; //定义队列的头、尾指针
char ch; //结点的data域值
root=NULL;
cin>>ch;
while(ch!='#') //输入值为#号,算法结束
{ s=NULL;
if(ch!=',') //输入数据不为逗号,表示不为虚结点,否则为虚结点
{ s=new BiTree;
s->data=ch;
s->lchild=NULL;
s->rchild=NULL;
}
rear++;
q[rear]=s; //新结点或虚结点进队
if(rear==1)
root=s;
else
{ if((s!=NULL)&&(q[front]!=NULL))
{ if(rear%2==0)
q[front]->lchild=s; //rear为偶数,s为双亲左孩子
else
q[front]->rchild=s;//rear为奇数,s为双亲右孩子
}
if(rear%2==1) front++; //出队
}
cin>>ch;
}
return root;
}
四.思考及选做
1.本实验给出了建立二叉树的二叉链表存储结构的一种方法,是否还有更简单的方法?
2.对于非递归先序遍历一般需要对每个结点进行二次进栈,这就需要一个标志位,如何处理这个标志位,使得既不需要构造新的存储结构也不需要增加一个新的标志栈。
五.我的实现
[cpp]
#include<stdio.h>
#include<stdlib.h>
#include <iostream>
#include<stack>
using namespace std;
/*******************数据结构的定义*************************/
typedef char elemtype;
typedef struct bitree
{
elemtype data;
struct bitree *lchild,*rchild;
}BiTree;
/**********************功能函数*******************************/
/*
建树. 输入格式为: a(b,c(d,e))
*/
BiTree *create(char *s,BiTree *&root)
{
int i;
bool isRight=false;
stack<BiTree*> s1; //用栈存放结点
stack<char> s2; //存放分隔符
BiTree *p,*temp;
root->data=s[0];
root->lchild=NULL;
root->rchild=NULL;
s1.push(root);
i=1;
while(i<strlen(s))
{
if(s[i]=='(')
{
s2.push(s[i]);
isRight=false;
}
else if(s[i]==',')
{
isRight=true;
}
else if(s[i]==')')
{
s1.pop();
s2.pop();
}
else if(isalpha(s[i]))
{
p=(BiTree *)malloc(sizeof(BiTree));
p->data=s[i];
p->lchild=NULL;
p->rchild=NULL;
temp=s1.top();
if(isRight==true)
{
temp->rchild=p;
cout<<temp->data<<"的右孩子是"<<s[i]<<endl;
}
else
{
temp->lchild=p;
cout<<temp->data<<"的左孩子是"<<s[i]<<endl;
}
if(s[i+1]=='(')
s1.push(p);
}
i++;
}
}
/*
递归打印函数 。
*/
void display(BiTree *root)
{
if(root!=NULL)
{
printf("%c",root->data);
if(root->lchild!=NULL)
{
printf("(");
display(root->lchild);
}
if(root->rchild!=NULL)
{
printf(",");
display(root->rchild);
printf(")");
}
}
}
/*
先序遍历。递归 。
*/
void preOrder1(BiTree *root)
{
if(root!=NULL)
{
printf("%c ",root->data);
preOrder1(root->lchild);
preOrder1(root->rchild);
}
}
/*
先序遍历。非递归 。
1)访问结点P,并将结点P入栈;
2)判断结点P的左孩子是否为空,若为空,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前的结点P,循环至1);若不为空,则将P的左孩子置为当前的结点P;
3)直到P为NULL并且栈为空,则遍历结束。
*/
void preOrder2(BiTree *root)
{
stack<BiTree*> s; //也可以用数组来实现
BiTree *p=root;
while(p!=NULL||!s.empty())
{
while(p!=NULL)
{
cout<<p->data<<" ";
s.push(p);
p=p->lchild;
}
if(!s.empty())
{
p=s.top();
s.pop();
p=p->rchild;
}
}
}
/*
中序遍历。递归。
*/
void inOrder1(BiTree *root)
{
if(root!=NULL)
{
inOrder1(root->lchild);
printf("%c ",root->data);
inOrder1(root->rchild);
}
}
/*
中序遍历。非递归。
1)若其左孩子不为空,则将P入栈并将P的左孩子置为当前的P,然后对当前结点P再进行相同的处理;
2)若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的P置为栈顶结点的右孩子;
3)直到P为NULL并且栈为空则遍历结束;
*/
void inOrder2(BiTree *root)
{
stack<BiTree*> s;
BiTree *p=root;
while(p!=NULL||!s.empty())
{
while(p!=NULL)
{
s.push(p);
p=p->lchild;
}
if(!s.empty())
{
p=s.top();
cout<<p->data<<" ";
s.pop();
p=p->rchild;
}
}
}
/*
后序遍历 。递归。
*/
void postOrder1(BiTree *root)
{
if(root!=NULL)
{
postOrder1(root->lchild);
postOrder1(root->rchild);
printf("%c ",root->data);
}
}
/*
后序遍历 。非递归。
要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。
如果P不存在左孩子和右孩子,则可以直接访问它;或者P存在左孩子或者右孩子,但
是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。若非上述两种情况,
则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩
子前面被访问,左孩子和右孩子都在根结点前面被访问。
*/
void postOrder2(BiTree *root)
{
stack<BiTree*> s;
BiTree *cur; //当前结点
BiTree *pre=NULL; //前一次访问的结点
s.push(root);
while(!s.empty())
{
cur=s.top();
if((cur->lchild==NULL&&cur->rchild==NULL)||
(pre!=NULL&&(pre==cur->lchild||pre==cur->rchild)))
{
cout<<cur->data<<" "; //如果当前结点没有孩子结点或者孩子节点都已被访问过
s.pop();
pre=cur;
} www.2cto.com
else
{
if(cur->rchild!=NULL)
s.push(cur->rchild);
if(cur->lchild!=NULL)
s.push(cur->lchild);
}
}
}
/***********************main函数*************************/
int main()
{
char s[100];
while((scanf("%s",s)))
{
BiTree *root=(BiTree *)malloc(sizeof(BiTree));
create(s,root);
printf("/n");
printf("先序递归遍历:");
preOrder1(root);
printf("/n");
printf("中序递归遍历:");
inOrder1(root);
printf("/n");
printf("后序递归遍历:");
postOrder1(root);
printf("/n");
printf("/n");
printf("先序非递归遍历:");
preOrder2(root);
printf("/n");
printf("中序非递归遍历:");
inOrder2(root);
printf("/n");
printf("后序非递归遍历:");
postOrder2(root);
printf("/n/n");
}
return 0;
}