二叉树后序遍历非递归的三种写法 (数据结构)

树结点结构体:

1 /**
2  * Definition for a binary tree node.
3  * struct TreeNode {
4  *     int val;
5  *     TreeNode *left;
6  *     TreeNode *right;
7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
8  * };
9  */

因为在后序遍历中,要保证左孩子和右孩子都已被访问并且左孩子在右孩子前访问才能访问根结点

第一种: 对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,此时该结点出现在栈顶,但是此时不能将其出栈并访问,因此其右孩子还为被访问。所以接下来按照相同的规则对其右子树进行相同的处理,当访问完其右孩子时,该结点又出现在栈顶,此时可以将其出栈并访问。这样就保证了正确的访问顺序。可以看出,在这个过程中,每个结点都两次出现在栈顶,只有在第二次出现在栈顶时,才能访问它。因此需要多设置一个变量标识该结点是否是第一次出现在栈顶。

前中序非递归遍历的方法: 不断搜左子树,然后出栈,指向右子树,如此循环。

 1    vector<int> postorderTraversal(TreeNode* root) {
 2         vector<int> result;
 3         if (root==nullptr) return result;
 4         TreeNode * mark = NULL;  // 标记变量
 5         stack<TreeNode *> S;
 6         S.push(root);
 7         root = root->left;
 8         
 9         while (!S.empty())
10         {
11             while (root)
12             {
13                 S.push(root);
14                 root = root->left;
15             }
16             mark = NULL;
17             while (!S.empty()) // 如果是右子树返回,所以要循环
18             {
19                 root = S.top();
20                 S.pop();
21 
22                 if (root->right == mark)  // 从右子树返回
23                 {
24                     result.push_back(root->val);
25                     mark = root;
26                 }
27                 else   // 从左子树返回
28                 {
29                     S.push(root);
30                     root = root->right;
31                     break;
32                 }
33             }
34 
35         } 
36         return result;
37     }

第二种:要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。如果P不存在左孩子和右孩子,则可以直接访问它;或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。

 1 vector<int> postorderTraversal(TreeNode *root)     //非递归后序遍历
 2 {
 3     vector<int> result;
 4     if(root == nullptr)
 5         return result;
 6     stack<TreeNode *> s;
 7     TreeNode *cur;                      //当前结点 
 8     TreeNode *pre = nullptr;            //前一次访问的结点 
 9     s.push(root);
10     while(!s.empty())
11     {
12         cur=s.top();
13         if((cur->left==nullptr&&cur->right==nullptr)||
14            (pre!=nullptr&&(pre==cur->left||pre==cur->right)))
15         {
16             result.push_back(cur->val);  //如果当前结点没有孩子结点或者孩子节点都已被访问过 
17             s.pop();
18             pre=cur;
19         }
20         else
21         {
22             if(cur->right != nullptr)
23                 s.push(cur->right);
24             if(cur->left != nullptr)
25                 s.push(cur->left);
26         }
27     }
28     return result;
29 }

 

第三种:

前序遍历:根-左子树-右子树

后序遍历:左子树-右子树-根 把前序遍历倒过来:右子树-左子树-根 !左右子树相反,不能直接倒!

先左子树入栈,在右子树入栈 (和前序遍历相反,也就是颠倒了左右子树->根-右子树-左子树),最后输出颠倒一下即可!

 1 class Solution:
 2     # @param root, a tree node
 3     # @return a list of integers
 4     def postorderTraversal(self, root):
 5         if not root: return []
 6         ans,q=[],[]
 7         q.append(root)
 8         while q:
 9             cur=q.pop()          
10             if cur.left: q.append(cur.left)
11             if cur.right: q.append(cur.right)
12             ans.append(cur.val)
13         return ans[::-1]

 

参考自:http://www.cnblogs.com/dolphin0520/archive/2011/08/25/2153720.html

posted @ 2017-12-26 14:42  demianzhang  阅读(5670)  评论(1编辑  收藏  举报