Leetcode OJ: Binary Tree Preorder/Inorder/Postorder Traversal

二叉树遍历,各种非递归实现,非递归实现基本都是用到栈,然后关键要弄明白的是什么时候进栈,什么时候出栈,什么时候指针是指向左孩子,什么时候指向右孩子。

先说先序遍历,先序遍历比较简单,从栈中拿出一个就打印一个,然后再把左右孩子进栈就行,要注意进栈是先右孩子,然后才是左孩子。看代码:

 1 /**
 2  * Definition for binary tree
 3  * struct TreeNode {
 4  *     int val;
 5  *     TreeNode *left;
 6  *     TreeNode *right;
 7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 8  * };
 9  */
10 class Solution {
11 public:
12     vector<int> preorderTraversal(TreeNode *root) {
13         vector<int> ret;
14         if (root == NULL)
15             return ret;
16         stack<TreeNode*> nodes;
17         nodes.push(root);
18         while (!nodes.empty()) {
19             TreeNode* p = nodes.top();
20             nodes.pop();
21             ret.push_back(p->val);
22             if (p->right != NULL)
23                 nodes.push(p->right);
24             if (p->left != NULL)
25                 nodes.push(p->left);
26         }
27         return ret;
28     }
29 };

稍微难一些的中序遍历,中序遍历就是要等左孩子都遍历完了才能访问本身,然后再访问右孩子。

换句话说,当节点还在栈中,就说明该节点的左孩子还没被访问,当被出栈时,就说明左孩子已经遍历完毕了,然后就可以打印当前节点。

下一步则由右孩子决定了,如果右孩子为空,就继续出栈打印,直到右孩子不为空。否则就开始访问右孩子。

代码如下:

 1 /**
 2  * Definition for binary tree
 3  * struct TreeNode {
 4  *     int val;
 5  *     TreeNode *left;
 6  *     TreeNode *right;
 7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 8  * };
 9  */
10 class Solution {
11 public:
12     vector<int> inorderTraversal(TreeNode *root) {
13         vector<int> ret;
14         TreeNode* p = root;
15         stack<TreeNode*> nodes;
16         while (p != NULL) {
17             if (p->left != NULL) {
18                 nodes.push(p);
19                 p = p->left;
20             }else {
21                 ret.push_back(p->val);
22                 if (p->right == NULL) {
23                     while (p->right == NULL && !nodes.empty()) {
24                         p = nodes.top();
25                         nodes.pop();
26                         ret.push_back(p->val);
27                     }
28                     
29                 }
30                 p = p->right;
31             }
32         }
33         return ret;
34     }
35 };

最难的就是后序遍历的非递归实现了,后序遍历的节点访问是需要左右节点均已被访问了才能访问本节点的内容,纯靠当前节点的信息不足以判断,这需要一个前驱节点用以记录你上一次的访问节点。那么判断当前节点是否应该被访问的条件就应该:当前节点的左右孩子均为空,或者是,当前节点的右孩子就是上一次访问的节点,或者是当前节点的右孩子为空,而上一次访问的节点上左孩子。其余情况都是进行压栈操作,还是要注意先右孩子,后左孩子

 1 /**
 2  * Definition for binary tree
 3  * struct TreeNode {
 4  *     int val;
 5  *     TreeNode *left;
 6  *     TreeNode *right;
 7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 8  * };
 9  */
10 class Solution {
11 public:
12     vector<int> postorderTraversal(TreeNode *root) {
13         vector<int> ret;
14         if (root == NULL)
15             return ret;
16         TreeNode* p;
17         TreeNode* pre = NULL;
18         stack<TreeNode*> nodes;
19         nodes.push(root);
20         while (!nodes.empty()) {
21             p = nodes.top();
22             if ((p->left == NULL && p->right == NULL) ||
23                 (pre != NULL && (pre == p->right || (pre == p->left && p->right == NULL))))
24             {
25                 ret.push_back(p->val);
26                 nodes.pop();
27                 pre = p;
28             } else {
29                 if (p->right != NULL)
30                     nodes.push(p->right);
31                 if (p->left != NULL)
32                     nodes.push(p->left);
33             }
34         }
35         return ret;
36     }
37 };

 

posted @ 2014-03-25 14:14  flowerkzj  阅读(157)  评论(0编辑  收藏  举报