1,040
社区成员




这是我参加“朝闻道”知识分享大赛的第五十四篇文章。
本文主要介绍一下二叉树的层次遍历。
首先先来说一下什么是层次遍历。
层次遍历就是按照从左到右、从上到下的顺序对二叉树进行一个遍历,下面给出的二叉树的层次遍历的顺序是: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';
- }
-
- }
- }