二叉树的前中后序遍历的实现(链式存储 非递归实现)

简单解释:

  • 前序遍历:需要先输出栈顶,再把左子树压入直到左儿子为空,删除栈顶,转向右儿子,继续下一次循环输出栈顶。。。
  • 中序遍历:与前序遍历相似,先将左子树压入栈中,输出当前栈顶,删除栈顶,转向右子树,继续下一次循环压入左子树。。。
  • 后序遍历:略微复杂,因为输出根节点时需要知道上次输出的节点是左子树还是右子树:

1、若为左子树,需要将右子树压入栈中才能访问当前跟节点。
2、若为右子树,可以直接输出根节点。

如图:
在这里插入图片描述

#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <algorithm>
using namespace std;
typedef long long ll;
#define maxn 1000005
#define mod 7654321
#define NIL -1

typedef struct Tree
{
    int data;
    Tree *lChild,*rChild;
}*TREE;

void creatTree(TREE &T)
{
    int element;
    cin>>element;
    if(element == NIL)
        T = NULL;
    else
    {
        T = (TREE)malloc(sizeof(Tree));
        T->data=element;
        printf("输入%d的左子节点的值:",element);
        creatTree(T->lChild);
        printf("输入%d的右子节点的值:",element);
        creatTree(T->rChild);
    }
}

void preTraverse(TREE T)
{
    if(T == NULL)
        return;
    TREE p=T;
    stack<TREE> s;
    while(!s.empty()||p)
    {
        while(p)
        {
            cout<<" "<<p->data;
            s.push(p);
            p = p->lChild;
        }
        if(!s.empty())
        {
            p=s.top();
            s.pop();
            p = p->rChild;
        }
    }
    cout<<endl;
}

void inTraverse(TREE T)
{
    if(T == NULL)
        return;
    TREE p=T;
    stack<TREE> s;
    while(!s.empty()||p)
    {
        //将左孩子压到空为止
        while(p)
        {
            s.push(p);
            p = p->lChild;
        }
        //输出左孩子的最后一个,再转向右孩子
        if(!s.empty())
        {
            p=s.top();
            s.pop();
            cout<<" "<<p->data;
            p = p->rChild;//转向右孩子
        }
    }
    cout<<endl;
}

void postTraverse(TREE T)
{
    if(T == NULL)
        return;
    stack<TREE> s;

    //标记当前的和上一个访问节点
    //pLast指向每次输出的节点的位置
    TREE pCur,pLast;
    //初始化
    pCur = T;
    pLast = NULL;
    //先将左儿子都压入栈中
    while(pCur)
    {
        s.push(pCur);
        pCur = pCur->lChild;
    }
    while(!s.empty())
    {
        //pCur指向当前的栈顶节点
        pCur = s.top();
        s.pop();
        //若当前节点没有右儿子或者右儿子是上一次访问输出的节点
        if(pCur->rChild==NULL||pCur->rChild==pLast)
        {
            //输出根节点
            cout<<" "<<pCur->data;
            //修改上一次访问的节点为当前输出节点
            pLast = pCur;
        }
        //若当前节点的左儿子刚刚访问过,则需要先进入右子树
        //else if(pCur->lChild==pLast)//这种写法也可以
        //或者说不能输出的话就需要将右子树压入栈中
        else
        {
            //将开始取出的未处理的栈顶继续入栈
            s.push(pCur);
            //转向右子树
            pCur = pCur->rChild;
            while(pCur)
            {
                s.push(pCur);
                //转向右子树继续先入栈左子树
                pCur = pCur->lChild;
            }
        }
    }
    cout<<endl;
}

int main()
{
    TREE T;
    cout<<"输入根节点:";
    creatTree(T);

    preTraverse(T);

    inTraverse(T);

    postTraverse(T);

    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值