145. 二叉树的后序遍历(非递归实现)

题目描述:

Given a binary tree, return the postorder traversal of its nodes values.
For example:
Given binary tree{1,#,2,3},

   1
    \
     2
    /
   3

return[3,2,1].

Note: Recursive solution is trivial, could you do it iteratively?

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */

方法1

思路

对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,此时该结点出现在栈顶,但是此时不能将其出栈并访问, 因为其右孩子还没被访问。所以接下来按照相同的规则对其右子树进行相同的处理,当访问完其右孩子时,该结点又出现在栈顶,此时可以将其出栈并访问。这样就 保证了正确的访问顺序。可以看出,在这个过程中,当我们第三次访问一个节点时,才能把它弹出栈。因此需要多设置一个变量表示这个节点已经被访问了几次。
重新定义节点结构:

//另外设计一种节点结构加入堆栈,不破坏原来的树结构
/**
 * Definition for binary tree
 * struct NewTreeNode {
 *     TreeNode *node;
 *     int has_visited_cnt;
 *     NewTreeNode() : node(NULL),has_visited_cnt(0) {}
 * };
 */

代码实现

  • C++实现:
vector<int> postorderTraversal(TreeNode *root){
     
     vector<int> result;
     if(root == nullptr)
         return result;
     stack<NewTreeNode*> s;
     TreeNode *p=root;
     while(p!=NULL||!s.empty())
     {   
         while(p!=NULL)               
          {
             NewTreeNode *new_p = (NewTreeNode *)malloc(sizeof(NewTreeNode));
             new_p->node = p;
             new_p->has_visited_cnt=1;
             s.push(new_p);
             p=p->left;
         }
         if(!s.empty())
         {
             NewTreeNode *temp=s.top();
             s.pop();
             if(temp->has_visited_cnt==1)      
              {
                 temp->has_visited_cnt=2;
                 s.push(temp);
                 p=temp->node->right;    
             }
             else                        
              {
                result.push_back(temp->node->val);
                p=NULL;//此时的当前节点路径仍然需要从备用的栈中获得
             }
         }
     }    
     return result;
} 
  • java实现
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {

    public List<Integer> postorderTraversal(TreeNode root) {

         class NewTreeNode{
            public TreeNode node;
            public boolean has_handle_right_node;
            NewTreeNode(TreeNode node,boolean flag){
                this.node = node;
                this.has_handle_right_node = flag;
            }

        }
        List<Integer> ret = new ArrayList<>();
        Deque<NewTreeNode> stk = new LinkedList<>();
        TreeNode p = root;
        while(true){
            while(p!=null){
                NewTreeNode temp = new NewTreeNode(p,false);
                stk.push(temp);
                p = p.left;
            }
            if(!stk.isEmpty()){
                NewTreeNode t = stk.peek();
                if(!t.has_handle_right_node){
                    t.has_handle_right_node = true;
                    p = t.node.right;
                }else{
                    ret.add(t.node.val);
                    stk.pop();
                    p = null;                    
                }
            }else
                break;
        }
        return ret;
    }
}

方法2

思路

要保证根结点在左孩子和右孩子访问之后才能访问,因此,

  • ↓对于任一结点P,先将其入栈(因为这个节点的孩子节点还没有访问,所以这个节点暂时还不能访问,所以先暂时把他放在一个地方-栈中)。
  • ↓如果P不存在左孩子和右孩子,则可以直接访问它(触发访问条件);或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点(另一种触发访问的条件)
  • ↓若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了
    • 每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。
    • 右儿子暂时不向下增长,左儿子一侧向下增长并完成访问,然后右儿子一侧向下增长并完成访问,最后访问父节点
  • ↓加入堆栈的顺序自然保证了先考察左子节点,再考察右子节点,最后考察根节点,所以不会出现考察当前节点cur时,它本来有两个儿子,但此时pre等于left的情况,因为加入堆栈的顺序,访问栈顶时,只能是left->right->cur的顺序,不可能出现已经访问过left,跳过right,直接访问cur,造成此时pre等于left的情况,它没法跳,这是由加入堆栈的顺序决定的

代码实现

  • C++实现
class Solution {
public:
    vector<int> postorderTraversal(TreeNode *root) 
    {

    	vector<int> result;
    	if(root == nullptr)
    		return result;
        //先加入的是上层的父节点,后加入的是下层的子节点,但是访问时是
       //下面的子节点访问过了,才能访问上面的父节点,可以利用堆栈数据
       //结构辅助解决问题
    	stack<TreeNode*> s;
        TreeNode *cur;//当前结点
        TreeNode *pre=NULL;//前一次访问的结点                 
        s.push(root);
        while(!s.empty())
        {
            cur=s.top();
           //考察当前节点是否有访问的资格,如果有资格访问的话,以当前
           //节点为根的子树就已经全部访问完了,不会再向下增长了,没有
           //继续利用的价值了
            if((cur->left==NULL && cur->right==NULL) || (pre!=NULL && (pre==cur->left || pre==cur->right)))
            {
            	result.push_back(cur->val);  
                s.pop();
                pre=cur; 
            }
            else//当前节点现在还不能访问,还需要继续暂存堆栈中
            {
            	if(cur->right!=NULL)//当前节点还能向下增长加入子节点
                s.push(cur->right);
                if(cur->left!=NULL)    
                s.push(cur->left);
            }
        }

     return result;    
               
    }
};

node.h:

using namespace std;

struct TreeNode
{
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

post_order.cpp:

#include "node.h"
#include <vector>
#include <stack>

using namespace std;

vector<int> postorderTraversal(TreeNode *root)
{
    if (root == nullptr)
        return {};
    vector<int> ret;
    stack<TreeNode *> stk;
    stk.push(root);
    TreeNode *pre = nullptr;
    while (!stk.empty())
    {
        TreeNode *temp = stk.top();
        if ((!temp->left && !temp->right) || (pre != nullptr && (pre == temp->left || pre == temp->right)))
        {
            ret.push_back(temp->val);
            stk.pop();
            pre = temp;
        }
        else
        {
            if (temp->right != nullptr)
                stk.push(temp->right);
            if (temp->left != nullptr)
                stk.push(temp->left);
        }
    }
    return ret;
}
  • java实现
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {

    public List<Integer> postorderTraversal(TreeNode root) {

        
        List<Integer> ret = new ArrayList<>();
        if(root==null)
            return ret;
        Deque<TreeNode> stk = new LinkedList<>();
        stk.push(root);
        TreeNode cur = null;
        TreeNode pre = null;
        while(!stk.isEmpty()){
            cur = stk.peek();
            if((cur.left==null && cur.right==null) || (pre!=null && (pre==cur.left || pre==cur.right))){
                ret.add(cur.val);
                stk.pop();
                pre = cur;
            }else{
                if(cur.right!=null)
                    stk.push(cur.right);
                if(cur.left!=null)
                    stk.push(cur.left);
            }
        }
        return ret;


    }
}

posted on 2021-05-16 13:46  朴素贝叶斯  阅读(120)  评论(0编辑  收藏  举报

导航