<mark>简单解释:</mark>

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

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

<mark>如图:</mark>

#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;
}