二叉树后续遍历算法

二叉树的后序遍历顺序为,root->left, root->right, root,因此需要保存根节点的状态。显然使用栈来模拟递归的过程,但是难点是怎么从root->right转换到root。

 

方法一

对于节点p可以分情况讨论

1. p如果是叶子节点,直接输出

2. p如果有孩子,且孩子没有被访问过,则按照右孩子,左孩子的顺序依次入栈

3. p如果有孩子,而且孩子都已经访问过,则访问p节点

 

如何来表示出p的孩是否都已经访问过了呢?

最暴力的方法就是对每个节点的状态进行保存,这么做显然是可以的,但是空间复杂度太大了。

我们可以保存最后一个访问的节点last,如果满足 (p->right==NULL && last ==p->left) || last=p->right,那么显然p的孩子都访问过了,接下来可以访问p

代码简单思路清晰!


 
#include <stdlib.h>
#include <iostream>
#include  <vector>
#include  <stack>
using namespace std;
// 定义结点类型
 struct node
{
    int data;
    struct node* left;
    struct node* right;
    node (int x):data(x),left(NULL),right(NULL){}
    
} ;

vector<int> Postorder(node* root)
{   
    vector <int> res;
    if(root ==NULL)
    return res;
    node* p = root;
    int flag = 1;
    node * t = NULL;
    stack<node *> sta;
    sta.push(p);
    cout << 1 << endl;
    while( !sta.empty())
    {
            p = sta.top();
            while(p->left != NULL)                    // 循环,将所有最左结点压栈
            {
                p = p -> left;
                sta.push(p);
            }
            flag = 1;                           // 辅助变量flag为1表示当前结点的左孩子为空或者已被访问
            t = NULL;                           // 指针变量t指向当前结点的前驱结点
            while( !sta.empty() && flag == 1)
            {
                p = sta.top();                  // 注意:这里只是获取栈顶元素,而并没有出栈
                if(p->right == t)              // 如果当前结点右孩子为空,或者已经被访问过,则访问当前结点
                {
                    cout << p->data;
                    res.push_back( p->data);
                    sta.pop();        // 当前结点出栈
                    t = p;                      // 指针变量指向当前结点
                }
                else                            // 如果当前结点右孩子不为空,则先去处理右孩子
                {
                    p = p->right;              // 处理右孩子
                    flag = 0;                   // *t的左孩子未被访问,flag置为0
                }
            }
        }
 return res;
 
}

int main()
{
        node a(1);
        node b(2);
        node c(5);
         node d(3);
         node e(4);
          node f(6);
          a.left = &b;
          a.right =  &c;
          b.left = &d;
          b.right = &e;
          c.right = &f; 
          vector<int> res = Postorder( &a );
          return 0;
}

方法二:

和二叉树先序遍历、中序遍历非递归算法一样,后序遍历非递归算法同样是使用栈来实现:从根结点开始,将所有最左结点全部压栈,每当一个结点出栈时,

都先扫描该结点的右子树,只有当一个结点的左孩子和右孩子结点均被访问过了,才能访问结点自身。

  二叉树后序遍历非递归算法实现如下:

#include <stdlib.h>
#include <stdio.h>
#define MAXSIZE 100
// 定义结点类型
typedef struct node
{
    int data;
    struct node* lchild;
    struct node* rchild;
} BTnode;

void Postorder(BTnode* t)
{
    BTnode* Seqstack[MAXSIZE];
    int top = -1;
    int falg = 1;
    BTnode* p;
    if(t != NULL)
    {
        do
        {
            while(t != NULL)                    // 循环,将所有最左结点压栈
            {
                top ++;
                Seqstack[top] = t;
                t = t->lchild;
            }
            flag = 1;                           // 辅助变量flag为1表示当前结点的左孩子为空或者已被访问
            p = NULL;                           // 指针变量p指向当前结点的前驱结点
            while(top > -1&& falg == 1)
            {
                t = Seqstack[top];              // 注意:这里只是获取栈顶元素,而并没有出栈
                if(t->rchild == p)              // 如果当前结点右孩子为空,或者已经被访问过,则访问当前结点
                {
                    top --;                     // 当前结点出栈
                    printf("%d ", p->data);
                    p = t;                      // 指针变量指向当前结点
                }
                else                            // 如果当前结点右孩子不为空,则先去处理右孩子
                {
                    t = t->rchild;              // 处理右孩子
                    flag = 0;                   // *t的左孩子未被访问,flag置为0
                }
            }
        }while(top > -1)
    }
    
}

上面代码实现了二叉树后序遍历非递归算法(重点看懂注释),接下来就说一说前面提到的该算法的一个特性了:就是当访问某个结点时,栈中所保存的元素

正好是这个结点的所有祖先。那么知道了这个特性,我们就很容易解决下面如下问题:

(1).当给定一个叶子结点,要求输出该叶子结点的所有祖先

(2).输出根结点到所有叶子结点的路径

(3).如果二叉树结点的值是数值,那么求每条路径上值之和,也可以利用二叉树后序遍历的非递归算法这个特性

#include <stdlib.h>
#include <stdio.h>
#define MAXSIZE 100
// 定义结点类型
 struct node
{
    int data;
    struct node* lchild;
    struct node* rchild;
    node (int x):data(x),lchild(NULL),rchild(NULL){}
    
} ;

void Postorder(node* t)
{
    node* Seqstack[MAXSIZE];
    int top = -1;
    int flag = 1;
    node * p;
    if(t != NULL)
    {
        do
        {
            while(t != NULL)                    // 循环,将所有最左结点压栈
            {
                top ++;
                Seqstack[top] = t;
                t = t->lchild;
            }
            flag = 1;                           // 辅助变量flag为1表示当前结点的左孩子为空或者已被访问
            p = NULL;                           // 指针变量p指向当前结点的前驱结点
            while(top > -1&& flag == 1)
            {
                t = Seqstack[top];              // 注意:这里只是获取栈顶元素,而并没有出栈
                if(t->rchild == p)              // 如果当前结点右孩子为空,或者已经被访问过,则访问当前结点
                {
                    top --;                     // 当前结点出栈
                    printf("%d ", p->data);
                    p = t;                      // 指针变量指向当前结点
                }
                else                            // 如果当前结点右孩子不为空,则先去处理右孩子
                {
                    t = t->rchild;              // 处理右孩子
                    flag = 0;                   // *t的左孩子未被访问,flag置为0
                }
            }
        }while(top > -1)
   ; }
    
}
int main()
{
     node a(1);
      node b(2);
        node c(5);
        node d(3);
         node e(4);
          node f(6);
          a.lchild =&b;
          a.rchild= &c;
          b.lchild =&d;
          b.rchild = &e;
          c.rchild = &f;
          //preorder(&a,0);
          //preorder1(&a);
          //preorder2(&a);
          //LeverOrder(&a);
          Postorder(&a);
          return 0;
}

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值