二叉树的三种非递归遍历

对于非递归遍历,我们通过栈实现
首先我们创建树的结点

typedef struct node
{
    int data;
    int num;           //为了计数用,在后序遍历中,子树的根节点在第一次遍历
    //的时候不会输出,只有在第二次遍历的时候才输出
    struct node *left;
    struct node *right;
}Node;
在这里插入代码片

然后定义一个存储树类型地址的栈,方便遍历的时候追踪到树的地址

typedef struct stack
{
    Node *elements[M];
    int top;
}seqstack;      //定义一个存储树类型地址的栈,方便遍历的时候追踪到树的地址
Node *root;     //定义一个树根
在这里插入代码片

接下来我们进行入栈出栈的一些操作,每次取栈顶

seqstack s;     //定义栈
void setnull()  //初始化栈
{
    s.top=0;
}
void push(Node *temp)   //入栈操作
{
    s.elements[s.top++]=temp;
}
Node *pop() //取栈顶并出栈顶
{
    return s.elements[--s.top];
}
int empty() //判断空栈
{
    return s.top==0;
}
在这里插入代码片

此时开始创建一个二叉树,接下来我们用递归来实现二叉树的创建

Node *creat()   //建立二叉树的递归算法
{
    Node *t;
    int x;
    scanf("%d",&x);
    if(x==0)
    {
        t=NULL;     //以x=0表示输入结束
    }
    else
    {
        t=(Node *)malloc(sizeof(Node));//动态生成结点t,分别给节点的数据域,左右孩子域
        t->data=x;//赋值,给左右孩子域赋值时用到了递归的思想
        t->left=creat();
        t->right=creat();
    }
    return t;
}
在这里插入代码片

然后便开始进行三种非递归遍历,对于前序遍历,我们先遍历左孩子输出,当所有左孩子遍历完毕后,取栈顶找右孩子,最后在遍历左孩子,直至结束

void preorder(Node *t)      //前序遍历的非递归算法
{
    Node *temp=t;   //定义一个树节点,用它来遍历
    while(temp!=NULL||s.top!=0)
    {
        while(temp!=NULL)//先遍历左孩子,并输出
        {
            printf("%4d",temp->data);
            push(temp);
            temp=temp->left;
        }
        if(s.top!=0)//当左孩子遍历完毕后,取栈顶,找右孩子,此时循环还没有结束,再遍历
        //它的左孩子,直至孩子全部遍历结束
        {
            temp=pop();
            temp=temp->right;
        }
    }
    printf("\n");
}
在这里插入代码片

中序遍历相对简单,先把左孩子入栈,所有左孩子入栈结束,再左孩子入栈结束,取栈顶,输出栈顶元素,遍历右孩子

void inorder(Node *t)//中序遍历的非递归算法
{
    Node *temp=t;
    while(temp!=NULL||s.top!=0)
    {
        while(temp!=NULL)//先把左孩子入栈,所有左孩子入栈结束
        {
            push(temp);
            temp=temp->left;
        }
        if(s.top!=0)//左孩子入栈结束,取栈顶,输出栈顶元素,遍历右孩子
        {
            temp=pop();
            printf("%4d",temp->data);
            temp=temp->right;
        }
    }
    printf("\n");
}
在这里插入代码片

后序遍历相对复杂,当结点第一次被访问时,不进行取栈操作,当第二次输出并制空,防止陷入死循环。

void laorder(Node *root)//后序遍历的非递归算法
{
    Node *temp=root;
    while(temp!=NULL||s.top!=0)
    {
        while(temp!=NULL)
        {
            temp->num=1;//当前节点首次被访问
            push(temp);
            temp=temp->left;
        }
        if(s.top!=0)
        {
            temp=pop();
            if(temp->num==1)//第一次出现在栈顶
            {
                temp->num++;
                push(temp);
                temp=temp->right;
            }
            else
            {
                if(temp->num==2)//第二次输出并制空,防止陷入死循环
                {
                    printf("%4d",temp->data);
                    temp=NULL;
                }
            }
        }
    }
    printf("\n");
}
在这里插入代码片

到此,三种非递归遍历基本实现,我们看一下完整的代码

#include
#include
#define NULL 0
#define M 100
typedef struct node
{
    int data;
    int num;           //为了计数用,在后序遍历中,子树的根节点在第一次遍历
    //的时候不会输出,只有在第二次遍历的时候才输出
    struct node *left;
    struct node *right;
}Node;
typedef struct stack
{
    Node *elements[M];
    int top;
}seqstack;      //定义一个存储树类型地址的栈,方便遍历的时候追踪到树的地址
Node *root;     //定义一个树根
seqstack s;     //定义栈
void setnull()  //初始化栈
{
    s.top=0;
}
void push(Node *temp)   //入栈操作
{
    s.elements[s.top++]=temp;
}
Node *pop() //取栈顶并出栈顶
{
    return s.elements[--s.top];
}
int empty() //判断空栈
{
    return s.top==0;
}
Node *creat()   //建立二叉树的递归算法
{
    Node *t;
    int x;
    scanf("%d",&x);
    if(x==0)
    {
        t=NULL;     //以x=0表示输入结束
    }
    else
    {
        t=(Node *)malloc(sizeof(Node));//动态生成结点t,分别给节点的数据域,左右孩子域
        t->data=x;//赋值,给左右孩子域赋值时用到了递归的思想
        t->left=creat();
        t->right=creat();
    }
    return t;
}
void preorder(Node *t)      //前序遍历的非递归算法
{
    Node *temp=t;   //定义一个树节点,用它来遍历
    while(temp!=NULL||s.top!=0)
    {
        while(temp!=NULL)//先遍历左孩子,并输出
        {
            printf("%4d",temp->data);
            push(temp);
            temp=temp->left;
        }
        if(s.top!=0)//当左孩子遍历完毕后,取栈顶,找右孩子,此时循环还没有结束,再遍历
        //它的左孩子,直至孩子全部遍历结束
        {
            temp=pop();
            temp=temp->right;
        }
    }
    printf("\n");
}
void inorder(Node *t)//中序遍历的非递归算法
{
    Node *temp=t;
    while(temp!=NULL||s.top!=0)
    {
        while(temp!=NULL)//先把左孩子入栈,所有左孩子入栈结束
        {
            push(temp);
            temp=temp->left;
        }
        if(s.top!=0)//左孩子入栈结束,取栈顶,输出栈顶元素,遍历右孩子
        {
            temp=pop();
            printf("%4d",temp->data);
            temp=temp->right;
        }
    }
    printf("\n");
}
void laorder(Node *root)//后序遍历的非递归算法
{
    Node *temp=root;
    while(temp!=NULL||s.top!=0)
    {
        while(temp!=NULL)
        {
            temp->num=1;//当前节点首次被访问
            push(temp);
            temp=temp->left;
        }
        if(s.top!=0)
        {
            temp=pop();
            if(temp->num==1)//第一次出现在栈顶
            {
                temp->num++;
                push(temp);
                temp=temp->right;
            }
            else
            {
                if(temp->num==2)//第二次输出并制空,防止陷入死循环
                {
                    printf("%4d",temp->data);
                    temp=NULL;
                }
            }
        }
    }
    printf("\n");
}
int main()
{
    Node *root;//创建根
    setnull();//制空栈
    root=creat();//创建二叉数
    printf("前序遍历:\n");
    preorder(root);
    printf("中序遍历:\n");
    inorder(root);
    printf("后序遍历:\n");
    laorder(root);
    return 0;
}

在这里插入代码片

下面是运行结果
二叉树的三种非递归遍历_第1张图片

你可能感兴趣的:(二叉树的三种非递归遍历)