• [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;断开链接

    退出循环

  • 相关阅读:
    【arm】arm平台下char默认数据类型与-fsigned-char
    【arm】arm指令集架构和处理器命名规则和历史
    【shell】正则表达式用法:匹配不包含字符串
    【arm】arm后缀.s和.S的区别以及asm.S说明
    【Optimization/x86】内联汇编Inline assembly——基础学习
    【Optimizaiton/x86】x86 SSE Intrinsic: 点乘算法的Intrinsic实现
    【Optimizaition/x86】Intel CPU的CPUID指令获取的C实现
    【linux】Linux中Core Dump分析
    【shell】linux 查看文件夹以及文件大小数目等信息
    【arm】arm-assembly-print-register-value-in-decimal
  • 原文地址:https://www.cnblogs.com/diegodu/p/3779585.html
Copyright © 2020-2023  润新知