1,041
社区成员




这是我参加“朝闻道”知识分享大赛的第五十四篇文章。
本文主要介绍一下二叉树的层次遍历。
首先先来说一下什么是层次遍历。
层次遍历就是按照从左到右、从上到下的顺序对二叉树进行一个遍历,下面给出的二叉树的层次遍历的顺序是:ABCDEFG
二叉树的层次遍历主要是借助队列来完成的,主要思路就是A节点先入队,入队后再将A节点出队并获取到它的左右孩子入队,再将队头节点出队并获取它的左右孩子入队,依次执行直到队列为空。
1.树结构的初始化
//树结构
typedef struct BiNode{
char elem; //数据
struct BiNode *lchild,*rchild; //父亲,左右孩子
}BiNode,*BiTree;
通过先序递归的方法创建一颗二叉树
void CreatBiTree(BiTree &T){
char data;
cin>>data;
if(data=='#'){
T=NULL;
}else{
T=new BiNode;
T->elem=data;
CreatBiTree(T->lchild);
CreatBiTree(T->rchild);
}
}
//队列节点
typedef struct QNode{
BiTree data;
struct QNode *next;
}QNode,*QueuePtr;
//队列
typedef struct Queue{
QueuePtr front; //队头指针
QueuePtr rear; //队尾指针
}LQueue;
//初始化队列
void InitQueue(LQueue *Lq){
Lq->front=Lq->rear=new QNode;
Lq->front->next=nullptr;
}
//树节点入队
void LqPush(LQueue *Lq,BiTree T){
QNode *p=new QNode;
p->data=T;
p->next=nullptr;
Lq->rear->next=p;
Lq->rear=p;
}
//获取队头元素,并将队头元素后移
BiTree LqPop(LQueue *Lq){
if(Lq->front==Lq->rear){
exit(0);
}
BiTree p=Lq->front->next->data;
Lq->front=Lq->front->next;
return p;
}
//按层次遍历序列
void LevelOrderTraverse(BiTree T){
LQueue Lq;
//判断树是否为空
if(T==NULL){
exit(0);
}
InitQueue(&Lq);
LqPush(&Lq,T); //存入根节点
//当队列不为空时
while(Lq.front!=Lq.rear){
//获取队头元素并且输出
BiTree fro=LqPop(&Lq);
cout<<fro->elem;
if(fro->lchild){
LqPush(&Lq,fro->lchild);
}
if(fro->rchild){
LqPush(&Lq,fro->rchild);
}
}
}
二叉树的递归遍历是比较简单的,也是比较好理解的,但是二叉树的非递归遍历就比较难理解了,接下来主要讨论一下非递归的中序遍历,并出具体实现。非递归实现树的遍历主要是借助了栈这一结构。接下来我们具体看看非递归遍历树是如何实现的。
非递归的中序遍历是从最下层的左子树开始,以左中右这种方式一层一层往上去遍历,所以我们先遍历节点若节点存在就将其入栈,再将访问其左孩子,直到遇到某个没有左孩子的节点就出栈访问该节点的右节点,若也为空就出栈,这时我们的栈就会指向这个出栈的节点的根节点,去去判断这个根节点有无右子树,这基本上就是一个循环过程了,我们只需要再树节点不为空或者栈不为空时让其一直循环便可。接下来是代码的实现。
//栈
typedef struct Stack{
BiTree data;
struct Stack *next;
}Stack,*StackPtr;
//有关栈的方法
//初始化栈
void InitStack(StackPtr &stack){
stack=NULL;
}
//判断栈是否为空
int isEmpty(StackPtr stack){
if(stack==NULL){
return 1;
}else{
return 0;
}
}
//进栈
void Push(StackPtr &stack,BiTree T){
if(T==NULL){
exit(0);
}
Stack *p=new Stack;
p->data=T;
p->next=stack;
stack=p;
}
//出栈
void Pop(StackPtr &stack,BiTree &q){
if(isEmpty(stack)){
exit(0);
}
q=stack->data;
Stack *p=stack;
stack=stack->next;
delete p;
}
void InOrderTraversal(BiTree T){
StackPtr S;
InitStack(S);
BiTree p=T;
BiTree q; //用来存储弹出节点的根节点,需要借助其去到右子树
while(p||!isEmpty(S)){
if(p){
Push(S,p);
p=p->lchild;
}else{
Pop(S,q);
cout<<q->elem;
p=q->rchild;
}
}
}
先序的非递归遍历就是,先遍历节点,若存在输出节点并入栈,并使指针指向其左孩子,若节点不存在就出栈,并访问栈顶节点的右孩子,直到栈为空且节点不存在时停止循环遍历即可。
//通过非递归的先序遍历输出树的节点
void PreOrderTraversalF(BiTree T){
StackPtr S;
InitStack(S);
BiTree p=T;
BiTree q; //用来存储弹出节点的根节点,需要借助其去到右子树
while(p||!isEmpty(S)){
if(p){
Push(S,p);
cout<<p->elem;
p=p->lchild;
}else{
Pop(S,q);
p=q->rchild;
}
}
}
void PostOrderTraversalF(BiTree T)
{
StackPtr S;
InitStack(S);
BiTree p=T;
char Flag[MAXSIZE] = {'0'}; //用于标记该节点是否遍历右子树,遍历完了才可以将该节点输出
while (p || !isEmpty(*S))
{
if (p)
{
Push(S, p);
Flag[S->top] = '0'; //标志结点还未遍历右子树
p = p->lchild;
}
else
{
while (Flag[S->top] == '1') {
Pop(S, &p);
cout<<p->elem;
}
if (S->top == -1) break;
Pop(S, &p);
Push(S, p);
p = p->rchild;
tag[S->top] = '1';
}
}
}