二叉树的先序、中序和后序遍历,包括递归和非递归两种写法。

LintCode上习题

我用递归和非递归都实现了一遍,非递归就是用一个显式的stack来维护,而后序遍历的非递归比较难处理。
另外有一个,我的时间普遍都在200ms+,递归和非递归的时间效率差不多;平台的服务器对运行时间也有一定的波动,但是都达不到10ms的水平,目前还不晓得前排大佬的代码是如何的。
下面来看6种实现代码:

pre-树的结构体

/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */

1. 前序遍历

(1-1) 递归实现

class Solution {
public:
    /**
     * @param root: A Tree
     * @return: Preorder in ArrayList which contains node values.
     */
    vector<int> preorderTraversal(TreeNode * root) {
        // write your code here
        vector<int> res;
        //边界条件
        if(root==NULL)
            return res; 

        //根    
        res.push_back(root->val);
        //左
        vector<int>left = preorderTraversal(root->left);
        //右
        vector<int>right = preorderTraversal(root->right);

        //合并答案
        for(int i=0; ifor(int i=0; ireturn res;
    }
};

(1-2)非递归实现

class Solution {
public:
    /**
     * @param root: A Tree
     * @return: Preorder in ArrayList which contains node values.
     */
    vector<int> preorderTraversal(TreeNode * root) {
        // write your code here
       vector<int >ret;
       stackQ;

       while(root || !Q.empty()){

           //一直往左,访问左子树
           while(root){
               Q.push(root);
               //保存根节点值
               ret.push_back(root->val);
               //再向左走
               root = root->left;
           }

           //出栈到最近的根节点
           TreeNode *now = Q.top();
           Q.pop();

           //再访问右节点,
           root = now->right;
       }

        return ret;
    }
};

2. 中序遍历

(2-1) 递归实现

class Solution {
public:
    /**
     * @param root: A Tree
     * @return: Inorder in ArrayList which contains node values.
     */
    vector<int> inorderTraversal(TreeNode * root) {
        // write your code here
        vector<int> res;
        //边界
        if(root==NULL)
            return res;
        //搜索左右子树    
        vector<int> res_l = inorderTraversal(root->left);
        vector<int> res_r = inorderTraversal(root->right);

        //合并
        for(int i=0; ival);
        for(int i=0; ireturn res;
    }
};

(2-2)非递归实现

class Solution {
public:
    /**
     * @param root: A Tree
     * @return: Inorder in ArrayList which contains node values.
     */
    vector<int> inorderTraversal(TreeNode * root) {
        // write your code here
        vector<int >ret;
        stack Q;

        while(root!=NULL || !Q.empty()){

            //一直往左遍历,左子树
            while(root!=NULL)
                {
                    Q.push(root);
                    root = root->left;
                }

            //最近的根节点
            TreeNode* now = Q.top();
            Q.pop();
            ret.push_back(now->val);

            //右儿子
            root = now->right;
        }

        return ret;

    }
};

3. 后序遍历

(3-1) 递归实现

class Solution {
public:
    /**
     * @param root: A Tree
     * @return: Postorder in ArrayList which contains node values.
     */
    vector<int> postorderTraversal(TreeNode * root) {
        // write your code here
        vector<int >res;
        //边界
        if(root==NULL)
            return res;

        //遍历左右子树
        vector<int >res_l = postorderTraversal(root->left);
        vector<int >res_r = postorderTraversal(root->right);
        //合并
        for(int i=0; ifor(int i=0; ival);

        return res_r;
    }
};

(3-2) 非递归实现
因为根节点要在右子树之后取值,所有这里根节点要访问两次,第一次是根节点->右儿子的过程,第二次是取根节点的值。
所以,用一个同步的vis栈来同步模拟树入栈的过程。当vis =0,表示这个节点第一次入栈,vis=1,表示这个节点第二次入栈。
所以,从栈中弹出一个节点now,它有三种情况:
1) now->right == NULL, 表示没有右节点。不访问now的右子树,并且记录now的val;
2) now->right !=NULL and v==0 ,表示now第一次弹栈,应该访问now->right节点。此时把now再次入栈,对应的vis置1,再把now->right入栈;
3)now->right!=NULL and v==1,表示now第二次弹栈。处理方式同情况1)。

class Solution {
public:
    /**
     * @param root: A Tree
     * @return: Postorder in ArrayList which contains node values.
     */
    vector<int> postorderTraversal(TreeNode * root) {
        // write your code here

        // write your code here
        stack Q;
        vector<int> res;
        stack<int> vis;
        while (root || !Q.empty()) {

            while (root) {
                Q.push(root);
                vis.push(0);
                root = root->left;
            }

            TreeNode * now = Q.top();
            Q.pop();
            int v = vis.top();
            vis.pop();


            if (now->right==NULL || v == 1) { //1.没有右子树。2.有右子树,但是已经遍历过左和右子树-> 保存根节点值
                res.push_back(now->val);
                root = NULL;
            }
            else {
                //标记根节点第二次访问了
                Q.push(now);
                vis.push(1);
                //处理根节点的右子树
                root = now->right;
            }

        }

        return res;
    }
};

你可能感兴趣的:(acm)