Leetcode: Binary Tree Preorder Traversal

Given a binary tree, return the preorder traversal of its nodes' values.

For example:
Given binary tree {1,#,2,3},

   1
    \
     2
    /
   3

 

return [1,2,3].

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

分析:迭代版先序遍历。用一个栈保存结点,压栈顺序为先右子树后左子树。时间复杂度为O(n),空间复杂度为O(h)。代码如下:

class Solution {
public:
    vector<int> preorderTraversal(TreeNode *root) {
        vector<int> result;
        if(!root) return result;
        
        stack<TreeNode *> S;
        S.push(root);
        
        while(!S.empty()){
            TreeNode *tmp = S.top();
            result.push_back(tmp->val);
            S.pop();
            if(tmp->right) S.push(tmp->right);
            if(tmp->left) S.push(tmp->left);
        }
        
        return result;
    }
};

 以上代码在leetcode中运行时间是32ms,下面是一个更快的版本用时8ms。但为什么会用时减少?理论上两种代码每个节点都是入栈和出栈一次,难道入栈出栈交替进行比入栈多次再出栈多次费时?

class Solution {
public:
    vector<int> preorderTraversal(TreeNode *root) {
        vector<int> result;
        stack<TreeNode *> S;
        
        for(TreeNode *p = root; p; p = p->left){
            S.push(p);
            result.push_back(p->val);
        }
        
        while(!S.empty()){
            TreeNode * tmp = S.top();
            S.pop();
            for(TreeNode *p = tmp->right; p; p = p->left){
                S.push(p);
                result.push_back(p->val);
            }
        }
        
        return result;
    }
};

 用栈的方法时间复杂度和空间复杂度皆为O(n),Morris遍历方法可以将空间复杂度降为O(1)。Morris遍历的主要思想是threaded binary tree,利用叶子节点的左右孩子指针,将其指向叶子节点在某种遍历中的前驱或后继。Morris遍历的过程分为两部分,一部分是线索化binary tree,另一部分是遍历tree。在线索化binary tree时,下一个处理的结点是当前节点的左孩子(如果有的话);在遍历tree的时候,下一个处理的节点是当前节点的右孩子。具体可参考这篇博文。Morris前序遍历在leetcode上运行时间是4ms,好于上面两种方法。

class Solution {
public:
    vector<int> preorderTraversal(TreeNode *root) {
        vector<int> result;
        TreeNode *prev = NULL, *cur = root;
        
        while(cur != NULL){
            if(cur->left == NULL){
                result.push_back(cur->val);
                cur = cur->right;
            }else{
                //find predecessor of cur
                prev = cur->left;
                while(prev->right != NULL && prev->right != cur){
                    prev = prev->right;
                }
                if(prev->right == NULL){//no threaded, so threaded now
                    result.push_back(cur->val);
                    prev->right = cur;
                    cur = cur->left;
                }else{
                    prev->right = NULL;
                    cur = cur->right;
                }
            }
        }
        
        return result;
    }
};

 

posted on 2014-12-04 20:20  Ryan-Xing  阅读(194)  评论(0编辑  收藏  举报