二叉树的遍历:
遍历二叉树根据根节点,左子树和右子树的访问顺序可分为先序遍历,中序遍历和后序遍历。
一:设计思想:
递归遍历:由二叉树的递归定义可知:二叉树是由3个基本单元组成的:根结点,左子树和右子树。因此,若是能依次遍历这三部分,便是访问了整个二叉树。其中左子树或右子树又是一棵新的具有根结点,左子树和右子树的二叉树。遍历左子树或右子树又是在重新遍历一棵新的二叉树。遍历二叉树时又在调用遍历二叉树方法本身,因而可以使用递归算法。
非递归算法:为了实现非递归遍历算法,我们需要一个栈或队列作为实现算法的辅助数据结构,栈用于存放在遍历过程中待处理的任务线索。二叉树是非线性数据结构,遍历过程中涉及的每一个结点,都可能有左、右两棵子树,任何时刻程序只能访问其中之一,所以程序必须保留以后继续访问另一棵子树的线索。这里使用堆栈来保留继续遍历的线索。
下面给出的是用递归算法实现二叉树先序遍历的源代码:
void PreorderRecursive(BinaryTree Binary)
{
BinaryNode *p=Binary;
if(p)
{
visit(p->date);
PreorderRecursive(p->lchild);
PreorderRecursive(p->rchild);
}
}
下面给出的是用递归算法实现二叉树中序遍历的源代码:
void MidorderRecursive(BinaryTree Binary)
{
BinaryNode *p=Binary;
if(p)
{
PreorderRecursive(p->lchild);
visit(p->date);
PreorderRecursive(p->rchild);
}
}
下面给出的是用递归算法实现二叉树后序遍历的源代码:
void PostorderRecursive(BinaryTree Binary)
{
BinaryNode *p=Binary;
if(p)
{
PreorderRecursive(p->lchild);
PreorderRecursive(p->rchild);
visit(p->date);
}
}
下面给出的是用非递归算法实现二叉树层次遍历的源代码:
void leveltra(BinaryTree Binary)
{
QueueList *Q;
Q=InitQueue();
BinaryNode *p;
p=InitBinaryNode();
p=Binary;
EnQueue(Q,p);
while (!QueueEmpty(Q))
{
p=DeQueue(Q);
visit(p->date);
if(p->lchild)
EnQueue(Q,p->lchild);
if(p->rchild)
EnQueue(Q,p->rchild);
}
}
下面给出的是用非递归算法实现二叉树先序遍历的源代码:
void Preorder(BinaryTree Binary)
{
StackList L;
L=InitStack();
BinaryNode *p;
p=Binary;
do{
//弹栈,找有右孩子的结点的右孩子
if(!StackEmpty(L)) //这里if和while语句换位置是为了可以访问到最后一个元素
{
p=Pop(L); //现在p指向右孩子
}
while(p)
{
visit(p->date);
if(p->rchild) //这里判断了只有遍历的结点有右孩子才会进栈,所以后边弹栈的时 //候不需要用do while语句来找右孩子,省去遍历空结点
{
Push(L,p->rchild);
}
p=p->lchild;
}
}while(!StackEmpty(L));
}
下面给出的是用非递归算法实现二叉树中序遍历的源代码:
void Midorder(BinaryTree Binary) //左根右 ,将每棵树的根压入栈中,先去遍历左子树,直到为空,
{
StackList L;
L=InitStack();
BinaryNode *p;
p=Binary;
do
{
while(p)
{
Push(L,p);
p=p->lchild;
}
p=Pop(L);
visit(p->date);
p=p->rchild;
}while(p|| !StackEmpty(L));
}
下面给出的是用非递归算法实现二叉树后序遍历的源代码:
下面给出的是用非递归算法实现二叉树后序遍历的源代码:
void Postorder(BinaryTree Binary) //左右根
{
StackList L;
L=InitStack();
BinaryNode *p;
p=Binary;
bool state=false;
do
{
while(p)
{
Push_state(L,p,state);//同中序遍历,将沿途根结点入栈,第一次入栈state为false
p=p->lchild;
}
if(!StackEmpty(L))
{
p=Pop_state(L,state); //弹出根结点,并取得对应state
if(state==false) /
{
state=true; //所以此时将其压回栈,并访问右子树,
Push_state(L,p,state);//这是需要将其对应state标志为true,
p=p->rchild;
}
else{ //右子树访问完,可以visit
visit(p->date);
p=NULL; //目的是表示此子树访问完,强制弹栈使之回到上一个根结点
}
}
}
while(!StackEmpty(L));
}
以下为二叉树结点结构体类型的声明:
typedef struct BinaryNode{
char date;
struct BinaryNode *lchild;
struct BinaryNode *rchild;
}BinaryNode,*BinaryTree;
BinaryNode *InitBinaryNode(){
BinaryNode *b;
b=(BinaryNode *)malloc(sizeof(BinaryNode));
b->lchild=NULL;
b->rchild=NULL;
return b;
}
BinaryNode *CreateBiTree(BinaryNode *Binary){
char ch;
ch=getchar();
if(ch=='#') return NULL; //binary=NULL;
else{
Binary=InitBinaryNode();
Binary->date=ch;
Binary->lchild=CreateBiTree(Binary->lchild);
Binary->rchild=CreateBiTree(Binary->rchild);
}
return Binary;
}
以下为实现非递归算法所需要的栈和队列的相关代码:
void visit(char ch)
{
printf("%c ",ch);
}
/*-------------------------------------------------------------------------------栈的定义和相关方法-------*/
//定义栈 这里的栈存取的是二叉树节点,注意返回和输入的类型
typedef struct StackNode{
bool state; //后序遍历需要一个指示状态的bool
BinaryNode *date;
struct StackNode *next;
} StackNode,*StackList;
//栈的相关方法:
StackNode *InitStack()
{
StackNode *L;
L=(StackNode *)malloc(sizeof(StackNode));
if(!L)
{
exit (-1);
}
L->state=false;
L->next=NULL;
L->date=NULL;
return L;
}
BinaryNode *Pop(StackList L)
{
BinaryNode *b;
StackNode *p;
b=InitBinaryNode();
p=InitStack();
p=L->next;
b=p->date;
L->next=p->next;
free(p);
return b;
}
void Push(StackList L,BinaryNode *b)
{
StackNode *p;
p=InitStack();
p->date=b;
p->next=L->next;
L->next=p;
}
BinaryNode *Pop_state(StackList L,bool &state)
{
BinaryNode *b;
StackNode *p;
b=InitBinaryNode();
p=InitStack();
p=L->next;
b=p->date;
state=p->state;
L->next=p->next;
free(p);
return b;
}
void Push_state(StackList L,BinaryNode *b,bool state)
{
StackNode *p;
p=InitStack();
p->date=b;
p->next=L->next;
p->state=state;
L->next=p;
}
bool StackEmpty(StackList L)
{
if(L->next==NULL)
return true;
else
return false;
}
/*-------------------------------------------------------------------------------栈的定义和相关方法-------*/
/*-------------------------------------------------------------------------------队列的定义和相关方法-------*/
//队列 这里队列存的也是二叉树节点 注意参数控制
typedef struct QueueNode
{
BinaryNode *date;
struct QueueNode *next;
}QueueNode;
typedef struct QueueList{
QueueNode *front;
QueueNode *rear;
}QueueList;
//初始化 此处写的队列也带头结点
QueueList *InitQueue()
{
QueueNode *Q;
QueueList *QL;
Q=(QueueNode *)malloc(sizeof(QueueNode));
QL=(QueueList *)malloc(sizeof(QueueList));
if((!Q)||!(QL))
exit (-1);
Q->date=NULL;
Q->next=NULL;
QL->front=QL->rear=Q; //开始让头尾都指向头结点
return QL;
}
//判空:
bool QueueEmpty(QueueList *Q)
{
if(Q->front==Q->rear)
return true;
else return false;
}
//入队
void EnQueue(QueueList *Q,BinaryNode *b)
{
QueueNode *q=(QueueNode *)malloc(sizeof(QueueNode));
q->date=b;
q->next=NULL;
Q->rear->next=q;
Q->rear=q;
}
//出队
BinaryNode *DeQueue(QueueList *Q)
{
if(!QueueEmpty(Q)){
QueueNode *q;
BinaryNode *b;
q=(QueueNode *)malloc(sizeof(QueueNode));
b=InitBinaryNode();
q=Q->front->next;
b=q->date;
Q->front->next=q->next;
if(Q->rear==q)
Q->rear=Q->front;
free(q);
return b;
}else exit(-1);
}
/*-------------------------------------------------------------------------------队列的定义和相关方法-------*/