二叉树前、中、后遍历详解【递归+迭代+morris】

转自:https://leetcode-cn.com/problems/binary-tree-preorder-traversal/solution/leetcodesuan-fa-xiu-lian-dong-hua-yan-shi-xbian-2/

1.递归解法

前中后遍历都很简单,就不写了。

2.迭代解法

力扣144题,二叉树的前序遍历:前序遍历的迭代解法,也是比较简单,利用栈先入根节点,根节点弹出,再入右子节点和左子节点,那么之后就是左子节点先弹出进行遍历,右子节点们一直被压栈。

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

力扣94题,二叉树的中序遍历:

Java版本的代码:

public static void inOrderIteration(TreeNode head) {
    if (head == null) {
        return;
    }
    TreeNode cur = head;
    Stack<TreeNode> stack = new Stack<>();
    while (!stack.isEmpty() || cur != null) {
        while (cur != null) {
            stack.push(cur);
            cur = cur.left;
        }
        TreeNode node = stack.pop();
        System.out.print(node.value + " ");
        if (node.right != null) {
            cur = node.right;
        }
    }
}

作者:gre-z
链接:https://leetcode-cn.com/problems/binary-tree-preorder-traversal/solution/leetcodesuan-fa-xiu-lian-dong-hua-yan-shi-xbian-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

内部的while循环表示处理左子树,然后node就是当前的节点,也就相当于此子树中的根节点,然后right了就是去遍历右子树了。

3月份的时候学习过,当然过了7个月到现在已经全忘记了。。。

力扣145题,二叉树的后序遍历:可以通过对前序遍历的栈来实现,后序遍历也用栈存储,前序中根先入遍历的时候弹出,左右入,弹出就是根右左的顺序了。

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> ans;
        if(!root) return ans;
        stack<TreeNode*> pre,post;
        pre.push(root);
        while(!pre.empty()){
            TreeNode* top=pre.top();pre.pop();
            post.push(top);
            if(top->left)pre.push(top->left);
            if(top->right)pre.push(top->right);
        }
        while(!post.empty()){
            ans.push_back(post.top()->val);
            post.pop();
        }
        return ans;
    }
};

第二种解法:

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> ans;
        if(!root) return ans;
        TreeNode* head=root;//指向的是访问的前一个节点
        stack<TreeNode*> st;
        st.push(root);
        while(!st.empty()){
            TreeNode* top=st.top();
            if(top->left!=NULL && top->left !=head && top->right!=head){
                st.push(top->left);
            }else if(top->right!=NULL && top->right != head){//左为空或者左已被访问过。
                st.push(top->right);
            }else{//如果左右子节点均为空,或者都已被访问过,那么就将当前ans
                ans.push_back(top->val);
                st.pop();//出栈的并且进入ans后才表示它被访问过,而且是下一个被访问的前一个节点,以此标注
                head=top;
            }
        }
        return ans;
    }
};

https://www.cnblogs.com/grandyang/p/4251757.html,讲的很好。

3.Morris解法

https://www.cnblogs.com/anniekim/archive/2013/06/15/morristraversal.html,经典教程。

二叉树的遍历和搜索时间复杂度是不一样的,前着一定是O(n),后者最优是O(logn),退化为链表的是O(n)。

上面链接中给出了两段代码,我觉得关键还是要知道自己遍历一下,对两种不同的情况,print节点的时候意味着什么。这个搞清楚才可以。

我终于知道这个意味着什么了!

99题恢复二叉搜索树,也用到了这个解法:

//中序遍历:
void inorderMorrisTraversal(TreeNode *root) {
    TreeNode *cur = root, *prev = NULL;
    while (cur != NULL)
    {
        if (cur->left == NULL)          // 1.
        {//当左子树为空时,那么中序遍历就可以打印cur节点
            printf("%d ", cur->val);
            cur = cur->right;
        }
        else
        {
            // find predecessor
            prev = cur->left;
            while (prev->right != NULL && prev->right != cur)
                prev = prev->right;

            if (prev->right == NULL)   // 2.a)
            {//这里表示去遍历左子树了。
                prev->right = cur;
                cur = cur->left;
            }
            else                       // 2.b)
            {//到这一步就意味着,左子树遍历完了,接下来要去遍历右子树了,所以可以打印当前节点(中序遍历)
                prev->right = NULL;
                printf("%d ", cur->val);
                cur = cur->right;
            }
        }
    }
}

下面是先序遍历:

void preorderMorrisTraversal(TreeNode *root) {
    TreeNode *cur = root, *prev = NULL;
    while (cur != NULL)
    {
        if (cur->left == NULL)
        {
            printf("%d ", cur->val);//如果左子树为空,那么可以打印当前
            cur = cur->right;
        }
        else
        {
            prev = cur->left;
            while (prev->right != NULL && prev->right != cur)
                prev = prev->right;

            if (prev->right == NULL)
            {//这里将要去遍历左子树,因为是先根所以先打印一下cur节点
                printf("%d ", cur->val);  // the only difference with inorder-traversal
                prev->right = cur;
                cur = cur->left;
            }
            else
            {//这里表示左子树和当前cur遍历完了,去遍历右子树
                prev->right = NULL;
                cur = cur->right;
            }
        }
    }
}

//至于morris后根,我还没看,代码好长啊

原文地址:https://www.cnblogs.com/BlueBlueSea/p/13888630.html