[LeetCode] Binary Tree Preorder/Inorder/Postorder Traversal

前中后遍历 递归版

 1  /*  Recursive solution */
 2 class Solution {
 3 public:
 4     vector<int> preorderTraversal(TreeNode *root) {
 5         
 6         vector<int> result;
 7         preorderTraversal(root, result);
 8         
 9         return result;
10     }
11     
12     void preorderTraversal(TreeNode *root, vector<int>& result)
13     {
14         if(root == NULL) return;
15         result.push_back(root->val);
16         
17         preorderTraversal(root->left, result);
18         preorderTraversal(root->right, result);
19     }
20     
21 };
 1  /*  Recursive solution */
 2 class Solution {
 3 public:
 4     vector<int> inorderTraversal(TreeNode *root) {
 5         
 6         vector<int> result;
 7         inorderTraversal(root, result);
 8         
 9         return result;
10     }
11     
12     void inorderTraversal(TreeNode *root, vector<int>& result)
13     {
14         if(root == NULL) return;
15         
16         inorderTraversal(root->left, result);
17         result.push_back(root->val);
18         inorderTraversal(root->right, result);
19     }
20     
21 };
 1  /*  Recursive solution */
 2 class Solution {
 3 public:
 4     vector<int> postorderTraversal(TreeNode *root) {
 5         
 6         vector<int> result;
 7         postorderTraversal(root, result);
 8         
 9         return result;
10     }
11     
12     void postorderTraversal(TreeNode *root, vector<int>& result)
13     {
14         if(root == NULL) return;
15         
16         postorderTraversal(root->left, result);
17         result.push_back(root->val);
18         postorderTraversal(root->right, result);
19     }
20     
21 };

下面是迭代版本

1 preorder: 节点入栈一次, 入栈之前访问。

2 inorder:节点入栈一次,出栈之后访问。

3 postorder:节点入栈2次,第二次出战后访问。

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

后续, 用bStack标记是否是第一次访问,如果是第一次访问,再次入栈,否则直接访问,记得将P = NULL;

 1 class Solution {
 2 public:
 3     vector<int> postorderTraversal(TreeNode *root) {
 4         
 5         vector<int> result;
 6         stack<TreeNode*> stack;
 7         std::stack<bool> bStack;
 8         
 9         TreeNode *p = root;
10         bool isFirst;
11         
12         while( NULL != p || !stack.empty())
13         {
14             while(NULL != p)
15             {
16                 stack.push(p);
17                 bStack.push(false);
18                 p = p->left;
19             }
20             
21             if(!stack.empty())
22             {
23                 p= stack.top();
24                 stack.pop();
25                 
26                 isFirst = bStack.top();
27                 bStack.pop();
28                 
29                 if(isFirst == 0)
30                 {
31                     stack.push(p);
32                     bStack.push(true);
33                     p=p->right;
34                 }
35                 else
36                 {
37                     result.push_back(p->val);
38                     p = NULL;
39                 }
40                 
41             }
42         }
43         
44         return result;
45     }
46     
47 };

 另外一种前序迭代实现

 1 class Solution {
 2     public:
 3         vector<int> preorderTraversal(TreeNode *root) {
 4             vector<int> result;
 5             const TreeNode *p;
 6             stack<const TreeNode *> s;
 7             p = root;
 8             if (p != nullptr) s.push(p);
 9             while (!s.empty()) {
10                 p = s.top();
11                 s.pop();
12                 result.push_back(p->val);
13                 if (p->right != nullptr) s.push(p->right);
14                 if (p->left != nullptr) s.push(p->left);
15             }
16             return result;
17         }
18 };

Morris 遍历  

morris分为3个步骤,建立link,访问最左节点,删除link,morris前序和中序遍历只要调整在那里visit节点即可,框架相同。。

可以参考:http://www.cnblogs.com/AnnieKim/archive/2013/06/15/MorrisTraversal.html

 Morris算法与递归和使用栈空间遍历的思想不同,它使用二叉树中的叶节点的right指针来保存后面将要访问的节点的信息,当这个right指针使用完成之后,再将它置为NULL,但是在访问过程中有些节点会访问两次,所以与递归的空间换时间的思路不同,Morris则是使用时间换空间的思想,先来看看Morris中序遍历二叉树的算法实现:

1 Morris 中序遍历 

class Solution {
    public:
        void morris_inorder(TreeNode* T) {
            TreeNode *p, *temp;
            p = T;
            while(p) {
                if(p->left == NULL) {
                    printf("%4d 
", p->val);
                    p = p->right;
                } else {
                    temp = p->left;
                    // find the most right node of the p's left node
                    while(temp->right != NULL && temp->right != p) {
                        temp = temp->right;
                    }   
                    if(temp->right == NULL) {
                        temp->right = p;
                        p = p->left;
                    } else {
                        printf("%4d 
", p->val);
                        temp->right = NULL;
                        p = p->right;
                    }   
                }   
            }   
        }   
};

同时, 以 下面的二叉树为例,走一遍流程:

      4

     /            

         2               7

      /                /  

    1      3         5     8

p指向4,  temp指向2,然后while Loop,tmp指向3, 3->right = 4, p = p->left=2; 建立链接

p指向2, tmp指向1, 然后while Loop,tmp指向1,   1->right = 2, p = p->left = 1;建立链接

p指向1, 由于p->left == NULL,visit(1), p = p ->right = 2,

p指向2, tmp指向1, 然后while Loop,tmp指向1,  visit(2), 1->right = NULL, p = p->right = 3;断开链接

p指向3, 由于p->left == NULL,visit(3), p = p ->right = 4,

p指向4, tmp指向2, 然后while Loop,tmp指向3,  visit(4), 3->right = NULL, p = p->right = 7;断开链接

p指向7, tmp指向5, 然后while Loop,tmp指向5,   5->right = 7, p = p->left = 5;建立链接

p指向5, 由于p->left == NULL,visit(5), p = p ->right = 7,

p指向7, tmp指向5, 然后while Loop,tmp指向5,  visit(7), 5->right = NULL, p = p->right = 8;断开链接

p指向8, 由于p->left == NULL,visit(3), p = p ->right = NULL,

退出循环

加上些打印信息,更好理解

class Solution {
    public:
        void morris_inorder(TreeNode* T) {
            TreeNode *p, *temp;
            p = T;
            while(p) {
                if(p->left == NULL) {
                    printf("visit %4d 
", p->val);
                    p = p->right;
                } else {
                    temp = p->left;
                    // find the most right node of the p's left node
                    while(temp->right != NULL && temp->right != p) {
                        temp = temp->right;
                    }   
                    if(temp->right == NULL) {
                        cout << "build link for " << temp->val <<"-->" << p->val << endl;
                        temp->right = p;
                        p = p->left;
                    } else {
                        printf("visit %4d 
", p->val);
                        cout << "destory link for " << temp->val <<"-->" << p->val << endl;
                        temp->right = NULL;
                        p = p->right;
                    }   
                }   
            }   
        }   
};







build link for 3-->4
build link for 1-->2
visit    1 
visit    2 
destory link for 1-->2
visit    3 
visit    4 
destory link for 3-->4
build link for 5-->7
visit    5 
visit    7 
destory link for 5-->7
visit    8 

morris 前序遍历

        void morris_preorder(TreeNode* T) {
            TreeNode *p, *temp;
            p = T;
            while(p) {
                if(p->left == NULL) {//visit the leftmost leaf node
                    printf("visit %4d 
", p->val);
                    p = p->right;
                } else {
                    temp = p->left;
                    // find the most right node of the p's left node
                    while(temp->right != NULL && temp->right != p) {
                        temp = temp->right;
                    }   
                    if(temp->right == NULL) {//build the link
                        printf("visit %4d 
", p->val);
                        temp->right = p;
                        p = p->left;
                    } else {//remove the link
                        temp->right = NULL;
                        p = p->right;
                    }   
                }   
            }   
        }

 3 morris 后序遍历

这里的reverse 和reverse单链表意思相同,另外之所以使用链表的reverse,而没有采用辅助stack后者vector是考虑要求空间复杂度O(1)的考虑

void reverse(TreeNode *from, TreeNode *to) // reverse the tree nodes 'from' -> 'to'.
{
    if (from == to)
        return;
    TreeNode *x = from, *y = from->right, *z;
    while (true)
    {
        z = y->right;
        y->right = x;
        x = y;
        y = z;
        if (x == to)
            break;
    }
}

void printReverse(TreeNode* from, TreeNode *to) // print the reversed tree nodes 'from' -> 'to'.
{
    reverse(from, to);
    
    TreeNode *p = to;
    while (true)
    {
        printf("%d ", p->val);
        if (p == from)
            break;
        p = p->right;
    }
    
    reverse(to, from);
}

void postorderMorrisTraversal(TreeNode *root) {
    TreeNode dump(0);
    dump.left = root;
    TreeNode *cur = &dump, *prev = NULL;
    while (cur)
    {
        if (cur->left == NULL)
        {
            cur = cur->right;
        }
        else
        {
            prev = cur->left;
            while (prev->right != NULL && prev->right != cur)
                prev = prev->right;

            if (prev->right == NULL)
            {
                prev->right = cur;
                cur = cur->left;
            }
            else
            {
                printReverse(cur->left, prev);  // call print
                prev->right = NULL;
                cur = cur->right;
            }
        }
    }
}

还是以上述bst为例,走一遍code:

p指向dummy,  temp指向4,然后while Loop,tmp指向8, 8->right = dummy, p = p->left=4; 建立链接

p指向4,  temp指向2,然后while Loop,tmp指向3, 3->right = 4, p = p->left=2; 建立链接

p指向2, tmp指向1, 然后while Loop,tmp指向1,   1->right = 2, p = p->left = 1;建立链接

p指向1, 由于p->left == NULL, p = p ->right = 2,

p指向2, tmp指向1, 然后while Loop,tmp指向1,  reversePrint(1,1), 1->right = NULL, p = p->right = 3;断开链接

p指向3, 由于p->left == NULL, p = p ->right = 4,

p指向4, tmp指向2, 然后while Loop,tmp指向3,  reversePrint(2,3), 3->right = NULL, p = p->right = 7;断开链接

p指向7, tmp指向5, 然后while Loop,tmp指向5,   5->right = 7, p = p->left = 5;建立链接

p指向5, 由于p->left == NULL, p = p ->right = 7,

p指向7, tmp指向5, 然后while Loop,tmp指向5,  reversePrint(5,5), 5->right = NULL, p = p->right = 8;断开链接

p指向8, 由于p->left == NULL,, p = p ->right = dummy,

p指向dummy, tmp指向4, 然后while Loop,tmp指向8,  reversePrint(4,8), 8->right = NULL, p = p->right = null;断开链接

退出循环

原文地址:https://www.cnblogs.com/diegodu/p/3779585.html