先序中序后序二叉树非递归实现

本文详细介绍了二叉树的先序、中序和后序遍历算法,并提供了非递归版本的实现代码。每种遍历方式都有明确的操作流程说明,帮助读者理解遍历逻辑及其背后的原理。

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

稍微解释一下: 
先序遍历。将根节点入栈,考察当前节点(即栈顶节点),先访问当前节点,然后将其出栈(已经访问过,不再需要保留),然后先将其右孩子入栈,再将其左孩子入栈(这个顺序是为了让左孩子位于右孩子上面,以便左孩子的访问先于右孩子;当然如果某个孩子为空,就不用入栈了)。如果栈非空就重复上述过程直到栈空为止,结束算法。 
中序遍历。将根节点入栈,考察当前节点(即栈顶节点),如果其左孩子未被访问过(有标记),则将其左孩子入栈,否则访问当前节点并将其出栈,再将右孩子入栈。如果栈非空就重复上述过程直到栈空为止,结束算法。 
后序遍历。将根节点入栈,考察当前节点(即栈顶节点),如果其左孩子未被访问过,则将其左孩子入栈,否则如果其右孩子未被访问过,则将其右孩子入栈,如果都已经访问过,则访问其自身,并将其出栈。如果栈非空就重复上述过程直到栈空为止,结束算法。 
其实,这只不过是保证了先序中序后序三种遍历的定义。对于先序,保证任意一个节点先于其左右孩子被访问,还要保证其左孩子先于右孩子被访问。对于中序,保证任意一个节点,其左孩子先于它被访问,右孩子晚于它被访问。对于后序,保证任意一个节点的左孩子右孩子都先于它被访问,其中左孩子先于右孩子被访问。如是而已。 

代码里应该体现得比较清楚。这里不光给出了非递归版本,也给出了递归版本。

这里需要强调一下:相对于教科书上实现方式,这种实现方式,visit和stack.pop总是结合在一起,这种非递归栈管理比较容易接受,而教科书上visit和pop可能是割裂的。最后会附上教科书上的实现方式。 

void PreOrderNoRecursion(TreePtr p)  
{  
    cout<<"PreOrderNoRecursion\n";  
   
    stack<TreeNode> stk;  
    TreeNode t = *p;  
    stk.push(t);  
   
    while (!stk.empty())  
    {  
        t = stk.top();  
        stk.pop();  
        cout<<t.data<<" ";  
   
        if (t.right != NULL)  
        {  
            stk.push((*t.right));  
        }  
   
        if (t.left != NULL)  
        {  
            stk.push((*t.left));  
        }  
    }  
}  

void InOrderNoRecursion(TreePtr p)  
{  
    cout<<"InOrderNoRecursion\n";  
   
    stack<TreeNode> stk;  
    TreeNode t = *p;  
    stk.push(t);  
   
    while (!stk.empty())  
    {  
        if (stk.top().flag == 0)  
        {  
            stk.top().flag++;  
            if (stk.top().left != NULL)  
            {  
                stk.push(*(stk.top().left));  
            }  
        }  
        else  
        {  
            t = stk.top();  
            stk.pop();  
            cout<<t.data<<" ";  
            if (t.right != NULL)  
            {  
                stk.push(*(t.right));  
            }  
        }  
    }  
}  

void PostOrderNoRecursion(TreePtr p)  
{  
    cout<<"PostOrderNoRecursion\n";  
   
    stack<TreeNode> stk;  
    TreeNode t = *p;  
    stk.push(t);  
   
    while (!stk.empty())  
    {  
        if (stk.top().flag == 0)  
        {  
            stk.top().flag++;  
            if (stk.top().left != NULL)  
            {  
                stk.push(*(stk.top().left));  
            }  
        }   
        else if (stk.top().flag == 1)  
        {  
            stk.top().flag++;  
            if (stk.top().right != NULL)  
            {  
                stk.push(*(stk.top().right));  
            }  
        }   
        else  
        {  
            cout<<stk.top().data<<" ";  
            stk.pop();  
        }  
    }  
}  

教科书上实现方式

1.先序遍历非递归算法
void PreOrderUnrec(Bitree *t)
{
    Stack s;
    StackInit(s);
    Bitree *p=t;
    
    while (p!=NULL || !StackEmpty(s))
    {
        while (p!=NULL)             //遍历左子树
        {
            visite(p->data);
            push(s,p);
            p=p->lchild;  
        }
        
        if (!StackEmpty(s))         //通过下一次循环中的内嵌while实现右子树遍历
        {
            p=pop(s);
            p=p->rchild;        
        }//endif
                
    }//endwhile 
}

2.中序遍历非递归算法
void InOrderUnrec(Bitree *t)
{
    Stack s;
    StackInit(s);
    Bitree *p=t;

    while (p!=NULL || !StackEmpty(s))
    {
        while (p!=NULL)             //遍历左子树
        {
            push(s,p);
            p=p->lchild;
        }
        
        if (!StackEmpty(s))
        {
            p=pop(s);
            visite(p->data);        //访问根结点
            p=p->rchild;            //通过下一次循环实现右子树遍历
        }//endif   
    
    }//endwhile
}

3.后序遍历非递归算法
typedef enum{L,R} tagtype;
typedef struct 
{
    Bitree ptr;
    tagtype tag;
}stacknode;

typedef struct
{
    stacknode Elem[maxsize];
    int top;
}SqStack;

void PostOrderUnrec(Bitree t)
{
    SqStack s;
    stacknode x;
    StackInit(s);
    p=t;
    
    do 
    {
        while (p!=null)        //遍历左子树
        {
            x.ptr = p; 
            x.tag = L;         //标记为左子树
            push(s,x);
            p=p->lchild;
        }
    
        while (!StackEmpty(s) && s.Elem[s.top].tag==R)  
        {
            x = pop(s);
            p = x.ptr;
            visite(p->data);   //tag为R,表示右子树访问完毕,故访问根结点       
        }
        
        if (!StackEmpty(s))
        {
            s.Elem[s.top].tag =R;     //遍历右子树
            p=s.Elem[s.top].ptr->rchild;        
        }    
    }while (!StackEmpty(s));
}//PostOrderUnrec 


我自己的实现:

#include <iostream>
#include <stack>

using namespace std;

struct Node
{
    int data;
    Node* l;
    Node* r;
    bool visitedleft;
    bool visitedright;
    Node(int d):data(d),l(NULL),r(NULL),visitedleft(false),visitedright(false){}
};

void preOrder(Node* root)
{
    if(NULL == root)
        return;
    stack<Node*> st;
    st.push(root);
    while(!st.empty() )
    {
       Node* tmp = st.top();
       st.pop();
       cout << tmp->data << endl;
       if(tmp->r)
       {
           st.push(tmp->r);
       }
       if(tmp->l)
           st.push(tmp->l);
    }
}

void inOrder(Node* root)
{
    if(NULL == root)
        return ;
    stack<Node*> st;
    st.push(root);
    while(!st.empty() )
    {
       Node* tmp = st.top();
       if(tmp->l && !tmp->visitedleft)
       {
          st.top()->visitedleft = true;
          st.push(tmp->l);
       }
       else
       {
          Node* v = st.top();
          st.pop();
          cout << v->data << endl;
          if(v->r)
          {
             st.push(v->r);
          }
       }
    }
}

void postOrder(Node* root)
{
    if(NULL == root)
        return ;
    stack<Node*> st;
    st.push(root);
    while(!st.empty() )
    {
       Node* tmp = st.top();
       if(tmp->l && !tmp->visitedleft)
       {
          st.top()->visitedleft = true;
          st.push(tmp->l);
       }
       else
       {
          if(tmp->r && !tmp->visitedright)
          {
             st.top()->visitedright = true;
             st.push(tmp->r);
          }
          else
          {
             st.pop();
             cout << tmp->data << endl;
          }
       }
    }
}



参考资料: http://blog.youkuaiyun.com/kofsky/article/details/2886453

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值