二叉树的前中后序遍历非递归实现及层次遍历队列实现

  • 我的上篇博客给出了二叉树的创建和前中后序遍历算法,但它们都是基于递归实现的,虽然代码简洁,但理解起来有点费劲,想当初第一次看到这么简洁的遍历算法后,心里连连跳出三个卧槽,实在是简洁的不像话,这里先给出我自己对递归的理解.
  • 递归像剥洋葱,假设我们剥了一层皮后还要洗干净这层皮,这一步才算完成,那么我们在剥完一次皮后,本来按步骤要去洗的,但剥完发现还有一层皮要剥,于是我们就先不洗了,而是立马把新出现的皮给剥了,之后同样看到皮就一路剥下去,每层皮洗的动作都先延后,直到剥完最后一层皮,发现没皮可剥了,那我们就把最后一层皮拿去洗,这样我们对最后一层皮的处理就彻底完成了,完成后这层皮后出现再你手里的就是倒数第二层皮,然后你那它去洗,则第二层皮的处理就完成了,紧接着去洗倒数第三层…依次类推,直到洗好第一层皮那么整个动作就完成了.
  • 前中后序的非递归遍历算法都是依靠辅助栈来实现的,而层次遍历是通过循环队列实现的,下面依次给出操作原理
  • 前序遍历(DLR)的非递归思想:
    1. 先定义一个栈,把二叉树的根结点入栈
    2. 然后栈顶出栈,一出栈便输出出栈结点,出栈的同时判断它是否有左右孩子,要有则入栈.注:要是左右孩子都存在则先右孩子入栈,因为先进后出嘛
    3. 最后在栈不为空的条件下一直循环执行步骤2
  • 中序遍历(LDR)的非递归思想
    1. 先定义一个栈,把二叉树的根结点入栈
    2. 把从根结点出发的左孩子一路入栈
    3. 碰到第一个没有左孩子的结点则访问输出该结点(即栈顶出栈结点),并让它指向自己的右孩子
    4. 若上一步中该结点有右孩子,则以他的右孩子出发,它有左孩子则左孩子统统入栈,即重复步骤2,步骤3
    5. 若步骤3中的结点没有右孩子,只要栈不为空便栈顶出栈,接着继续做步骤3的判断
  • 后序遍历(LRD)的非递归遍历思想
    • 和前序遍历的过程一样就四点不同的地方,其他都一样
      1. 需要两个辅助栈实现
      2. 当栈1出栈顶点左右孩子都存在时,先左孩子入栈
      3. 栈1出栈结点立马压入栈2,并不像前序那样立马访问输出
      4. 最后统一让栈2一次性出栈,每个结点一出栈就访问输出
    • 后序遍历能这么干的依据是:逆后序遍历就是把先序遍历中对左右子树的遍历顺序交换的结果
  • 二叉树的层次遍历实现思想(和图的广度优先遍历思想一致)

    1. 先创建一个二叉树结点类型队列,根结点若不为空则入队
    2. 紧接着对头出队,马上访问输出出队结点的数据域,出队的同时判断该结点是否有左右孩子,有的话则统统入队,注:左右孩子都有时先左孩子入队,先进先出嘛
    3. 在队不为空的情况下循环执行以上两步

    好了,上代码才是王道

#include <iostream>
#include <stdlib.h> 
#define maxSize 100
typedef struct BTNode{
    char data;
    struct BTNode *lchild;
    struct BTNode *rchild;
}BTNode;

void createBTree(BTNode *&p){//前序遍历创建二叉树,所以创建完成后p肯定就是二叉树的根结点 
    char ch;
    scanf("%c",&ch);
    if(ch=='#'){
        p=NULL;
    }else{
        p=(BTNode *)malloc(sizeof(BTNode));
        p->data=ch;
        createBTree(p->lchild);
        createBTree(p->rchild);
    }
}


void preOrderSt(BTNode *p){//前序遍历的非递归实现 
    BTNode *stack[maxSize];
    int top;
    top=-1;
    BTNode *q;
    if(p!=NULL){
        stack[++top]=p;//根结点入栈 
        while(top!=-1){
            q=stack[top--];//根结点出栈 
            printf("%c ",q->data);//访问 
            if(q->rchild!=NULL){//若结点有右孩子则右孩子入栈(先进后出嘛)
                stack[++top]=q->rchild;
            }
            if(q->lchild!=NULL){//有左孩子则左孩子入栈 
                stack[++top]=q->lchild;
            }
        }
    }
}

void inOrderSt(BTNode *p){//中遍历的非递归实现 
    BTNode *stack[maxSize];
    BTNode *q;
    int top;
    top=-1;
    while(p!=NULL||top!=-1){
        while(p!=NULL){//左孩子存在的话一直进栈 
            stack[++top]=p;
            p=p->lchild;
        }
        if(top!=-1){//左孩子不存在则一路出栈,出栈的同时得判读它有没右孩子 
            p=stack[top--];//没有左孩子了,则栈顶出栈 
            printf("%c ",p->data);//一出栈便立马访问 
            p=p->rchild;//若右孩子存在,会进入上面的while循环,再度判读其右孩子有没有左孩子 
        }
    }
} 

void postOrderSt(BTNode *p){//后序遍历的非递归实现 
    BTNode *stack1[maxSize];int top1=-1;
    BTNode *stack2[maxSize];int top2=-1;
    BTNode *q,*s;
    stack1[++top1]=p;//入栈 
    while(top1!=-1){//若栈不为空 
        q=stack1[top1--];//根结点出栈的同时看看有没有左右孩子,有就进栈(先左后右) 
        stack2[++top2]=q;//栈1出栈的元素栈2马上入栈 
        if(q->lchild!=NULL){
            stack1[++top1]=q->lchild;
        }
        if(q->rchild!=NULL){
            stack1[++top1]=q->rchild;
        }
    }
    while(top2!=-1){//栈2中出栈输出 
        s=stack2[top2--];
        printf("%c ",s->data);
    } 
} 

void level(BTNode *p){//二叉树的层次遍历 
    BTNode *bt[maxSize];
    BTNode *q;
    int front,rear;//建立循环队列 
    front=rear=0;//初始化队列 
    if(p!=NULL){
        rear=(rear+1)%maxSize;
        bt[rear]=p;//根结点入队 
        printf("层序遍历序列为: ");
        while(front!=rear){//队不为空时循环 
            front=(front+1)%maxSize;
            q=bt[front];//头结点出队 
            printf("%c ",q->data);//出队就打印 
            if(q->lchild!=NULL){//若出队结点有左孩子则左孩子入队 
                rear=(rear+1)%maxSize;
                bt[rear]=q->lchild;
            }
            if(q->rchild!=NULL){//若出队结点有右孩子则右孩子入队 
                rear=(rear+1)%maxSize;
                bt[rear]=q->rchild;
            }
        }
    }
}

int main(int argc, char** argv) {
    BTNode *p;
    createBTree(p);

    printf("前序非递归遍历序列: ");
    preOrderSt(p);
    printf("\n");

    printf("中序非递归遍历序列: ");
    inOrderSt(p);
    printf("\n");

    printf("后序非递归遍历序列: ");
    postOrderSt(p);
    printf("\n"); 

    printf("层次遍历序列: ");
    level(p);
    printf("\n");     
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37597859/article/details/79849668