二叉树的层次遍历 “朝闻道”知识分享大赛通知

菜菜菜攻城狮 2023-12-31 14:52:03

这是我参加“朝闻道”知识分享大赛的第五十四篇文章。

 

本文主要介绍一下二叉树的层次遍历。

首先先来说一下什么是层次遍历。

 层次遍历就是按照从左到右、从上到下的顺序对二叉树进行一个遍历,下面给出的二叉树的层次遍历的顺序是: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);
    }
}

2.队列的初始化及方法

//队列节点
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;
}

3.按层次遍历二叉树

//按层次遍历序列
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);
        }
    }
}

二叉树的递归遍历是比较简单的,也是比较好理解的,但是二叉树的非递归遍历就比较难理解了,接下来主要讨论一下非递归的中序遍历,并出具体实现。非递归实现树的遍历主要是借助了栈这一结构。接下来我们具体看看非递归遍历树是如何实现的。

 

2.非递归的中序遍历

非递归的中序遍历是从最下层的左子树开始,以左中右这种方式一层一层往上去遍历,所以我们先遍历节点若节点存在就将其入栈,再将访问其左孩子,直到遇到某个没有左孩子的节点就出栈访问该节点的右节点,若也为空就出栈,这时我们的栈就会指向这个出栈的节点的根节点,去去判断这个根节点有无右子树,这基本上就是一个循环过程了,我们只需要再树节点不为空或者栈不为空时让其一直循环便可。接下来是代码的实现。

//栈
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;
 
}

 2.2通过非递归的中序遍历输出树的节点

 
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;
        }
    }
}

3.非递归的先序遍历

先序的非递归遍历就是,先遍历节点,若存在输出节点并入栈,并使指针指向其左孩子,若节点不存在就出栈,并访问栈顶节点的右孩子,直到栈为空且节点不存在时停止循环遍历即可。

//通过非递归的先序遍历输出树的节点
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;
        }
    }
}

4.非递归的后序遍历

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';
        }

    }
}

 

 

...全文
135 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

857

社区成员

发帖
与我相关
我的任务
社区描述
中南民族大学CSDN高校俱乐部聚焦校内IT技术爱好者,通过构建系统化的内容和运营体系,旨在将中南民族大学CSDN社区变成校内最大的技术交流沟通平台。
经验分享 高校 湖北省·武汉市
社区管理员
  • c_university_1575
  • WhiteGlint666
  • wzh_scuec
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

欢迎各位加入中南民族大学&&CSDN高校俱乐部社区(官方QQ群:908527260),成为CSDN高校俱乐部的成员具体步骤(必填),填写如下表单,表单链接如下:
人才储备数据库及线上礼品发放表单邀请人吴钟昊:https://ddz.red/CSDN
CSDN高校俱乐部是给大家提供技术分享交流的平台,会不定期的给大家分享CSDN方面的相关比赛以及活动或实习报名链接,希望大家一起努力加油!共同建设中南民族大学良好的技术知识分享社区。

注意:

1.社区成员不得在社区发布违反社会主义核心价值观的言论。

2.社区成员不得在社区内谈及政治敏感话题。

3.该社区为知识分享的平台,可以相互探讨、交流学习经验,尽量不在社区谈论其他无关话题。

试试用AI创作助手写篇文章吧