非递归遍历二叉树

本文详细介绍了如何使用栈实现二叉树的非递归遍历,包括先序遍历(根左右)、中序遍历(左根右)和后序遍历(左右根),并提供了相应的函数和代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二叉树结构

//二叉树结构
typedef struct BitNode{
    char data;
    struct BitNode *lchild; //左孩子
    struct BitNode *rchild;  //右孩子
}BitNode,*BiTree;

二叉树的非递归遍历,要用到栈先进后出的结构

栈结构如下


//栈的结构
typedef struct tree
{
    int top;//栈顶
    int base;//栈底
    BiTree *arr; //因为我们后序遍历要判断地址是否为空,所以我们用二级指针
}stank;

   初始化栈

//初始化栈
void Initie(stank &s){
    s.arr=(BiTree*) malloc (Max*sizeof(BitNode));
   if(!s.base)
       exit(0);
    s.top=s.base=0;
}

判断栈是否为空

//判断栈是否为空
int Empty(stank &s){
    if(s.top==s.base)
        return 0;
    else
        return 1;
}

入栈

//入栈
void Enter(stank &s,BiTree T){
    s.arr[s.top]=T;
            s.top++;
}

出栈

//出栈
void Go_out(stank &s){
        s.top--;
}

构建一颗二叉树

//构建一颗二叉树
BiTree CreeatBiTree(){
    BiTree T;
    char ch;
    scanf("%c",&ch);
    getchar(); //吸收空格
    if(ch=='0')  //当输入0时,代表某有孩子
    {
        T=NULL;
    }
    else
    {
        T=(BiTree) malloc (sizeof(BitNode));
        T->data=ch;
        printf("请输入%c的左孩子:",T->data);
        T->lchild=CreeatBiTree();
        printf("请输入%c的右孩子:",T->data);
        T->rchild=CreeatBiTree();
    }
    return T;
}

基本的框架已经构建完成,现在讲解遍历

一、先序遍历,根左右

先序遍历,我们一开始先让根节点进栈,在将根节点出栈,剩下的一次进栈,先进后出

所以理解成根节点不用栈的结构

因为我们把根节点A一进栈就出栈,所以现在B出栈完,C在出战

void Preorder(BiTree L){
    stank s;
    BiTree B;
    //给B开辟空间
    B=(BiTree) malloc (sizeof(BitNode));
    Initie(s);//初始化栈
    if(L==NULL){
        return;
    }
    else
    {
    //先把根节点进栈
        Enter(s,L);
        while(Empty(s)){//栈空退出循环
            B=s.arr[s.top-1];//B来接收
            printf("%c ",B->data);
            //出栈
            Go_out(s);
            if(B->rchild)
            {
                Enter(s, B->rchild);
            }
            if(B->lchild)
            {
                Enter(s, B->lchild);
            }
        }
    }
}

二、中序遍历,左根右

先将根节点A入栈,在依次递归将A的左孩子进栈,一直把左孩子进栈完,在依次从下往上出栈,出栈一个就要判断右孩子是否为空

在依次往上将做孩子的右孩子入栈

//中序遍历,左根右
void InOrder(BiTree L){
    BiTree B;
    stank s;
    Initie(s); //初始化栈
    if(!L){
        return;
    }
    B=L;
    while(B!=NULL || Empty(s))
    {
        while(B!=NULL)
        {
            Enter(s,B);//进栈
            B=B->lchild;//左孩子全部进栈
        }//退出循环是指针指向的左孩子为空
        B=s.arr[s.top-1];
        printf("%c ",B->data);
        Go_out(s);//出栈
        B=B->rchild;//指向右孩子
    }
}

三、后序遍历,左右根

还是先把根节点入栈,在把左孩子全部入栈,然后依次出栈左孩子,出栈一次,就要判断左孩子是否有右孩子,有右孩子就要入栈

//后序遍历
void Postorder(BiTree L){
    if(!L){
        return;
    }
    BiTree B=L;
    BiTree H=NULL;
    stank s;
    Initie(s);//初始化栈
    while(B ||Empty(s))
    {
        while(B)
        {
            Enter(s, B);
            B=B->lchild;
        }
       BiTree C=s.arr[s.top-1];
        if( C->rchild==NULL || C->rchild==H )
        {
            printf("%c ",C->data);
            Go_out(s);
            H=C;//记录当前结点
            C=NULL;
        }
        else
        {
            B=C->rchild;
        }
    }
}

注意这个条件if( C->rchild==NULL || C->rchild==H )

当只有三个值时,就剩A未出栈,A的右孩子也不为null,所以要记录好A的右孩子,这样就可以进入if条件

 

四、全部代码如下

//二叉树的非递归遍历,前,中,后
#include <stdio.h>
#include <stdlib.h>
#define Max 100
//二叉树结构
typedef struct BitNode{
    char data;
    struct BitNode *lchild; //左孩子
    struct BitNode *rchild;  //右孩子
}BitNode,*BiTree;

//栈的结构
typedef struct tree
{
    int top;//栈顶
    int base;//栈底
    BiTree *arr;
}stank;

//初始化栈
void Initie(stank &s){
    s.arr=(BiTree*) malloc (Max*sizeof(BitNode));
   if(!s.base)
       exit(0);
    s.top=s.base=0;
}

//判断栈是否为空
int Empty(stank &s){
    if(s.top==s.base)
        return 0;
    else
        return 1;
}
//入栈
void Enter(stank &s,BiTree T){
    s.arr[s.top]=T;
            s.top++;
}
//出栈
void Go_out(stank &s){
        s.top--;
}
//构建一颗二叉树
BiTree CreeatBiTree(){
    BiTree T;
    char ch;
    scanf("%c",&ch);
    getchar(); //吸收空格
    if(ch=='0')  //当输入0时,代表某有孩子
    {
        T=NULL;
    }
    else
    {
        T=(BiTree) malloc (sizeof(BitNode));
        T->data=ch;
        printf("请输入%c的左孩子:",T->data);
        T->lchild=CreeatBiTree();
        printf("请输入%c的右孩子:",T->data);
        T->rchild=CreeatBiTree();
    }
    return T;
}

//先序遍历,根左右
void Preorder(BiTree L){
    stank s;
    BiTree B;
    //给B开辟空间
    B=(BiTree) malloc (sizeof(BitNode));
    Initie(s);
    if(L==NULL){
        return;
    }
    else
    {
    //先把根节点进栈
        Enter(s,L);
        while(Empty(s)){//栈空退出循环
            B=s.arr[s.top-1];//B来接收
            printf("%c ",B->data);
            //出栈
            Go_out(s);
            if(B->rchild)
            {
                Enter(s, B->rchild);
            }
            if(B->lchild)
            {
                Enter(s, B->lchild);
            }
        }
    }
}
//中序遍历,左根右
void InOrder(BiTree L){
    BiTree B;
    stank s;
    Initie(s); //初始化栈
    if(!L){
        return;
    }
    B=L;
    while(B!=NULL || Empty(s))
    {
        while(B!=NULL)
        {
            Enter(s,B);//进栈
            B=B->lchild;//左孩子全部进栈
        }//退出循环是指针指向的左孩子为空
        B=s.arr[s.top-1];
        printf("%c ",B->data);
        Go_out(s);//出栈
        B=B->rchild;//指向右孩子
    }
}
//后序遍历
void Postorder(BiTree L){
    if(!L){
        return;
    }
    BiTree B=L;
    BiTree H=NULL;
    stank s;
    Initie(s);//初始化栈
    while(B ||Empty(s))
    {
        while(B)
        {
            Enter(s, B);
            B=B->lchild;
        }
       BiTree C=s.arr[s.top-1];
        if( C->rchild==NULL || C->rchild==H )
        {
            printf("%c ",C->data);
            Go_out(s);
            H=C;//记录当前结点
            C=NULL;
        }
        else
        {
            B=C->rchild;
        }
    }
}

int main() {
    BiTree T;
    printf("请按先序依次输入树的结点:\n");
    printf("请输入根节点:");
    T = CreeatBiTree();
    printf("前序遍历结果\n");
    Preorder(T);
    printf("\n");
    printf("中序遍历结果\n");
    InOrder(T);
    printf("\n");
    printf("后序遍历结果\n");
    Postorder(T);
    printf("\n");
    return 0;
}

运行结构如下

欢迎来讨论

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值