Three traversal methods of binary tree (recursive + non-recursive)

General idea

First of all, there are three kinds of tree traversal

  • Preorder traversal The
    order is the root node-left subtree-right subtree
  • Post-order traversal The
    order is left subtree-right subtree-root node
  • In-order traversal The
    order is left subtree-root node-right subtree

And for each node are executed recursively in the same order

Recursion

In the recursive mode, everyone is familiar with it, it is nothing more than the function body is called according to the order of traversal.

void preorder(TreeNode* root) {
    
    
        if(root == nullptr) {
    
    
            return;
        }
        ans.push_back(root ->val);
        preorder(root -> left);
        preorder(root -> right);
    }

Modify the order in this format. If you want to know why this can be achieved, you can go through it yourself on the premise of knowing how to analyze the recursive process, which is the process of extension and backtracking. If you still don’t know how to analyze the recursive process, don’t memorize it and learn more about recursion.
Recursive implementation:

Preorder traversal

Leetcode - 144

class Solution {
    
    
public:
    vector<int> ans;
    vector<int> preorderTraversal(TreeNode* root) {
    
    
        if(root == nullptr) return {
    
    };
        preorder(root);
        return ans;
    }
    void preorder(TreeNode* root) {
    
    
        if(root == nullptr) {
    
    
            return;
        }
        ans.push_back(root ->val);
        preorder(root -> left);
        preorder(root -> right);
    }
};

In-order traversal

Leetcode - 94

class Solution {
    
    
public:
    vector<int> ans;
    vector<int> inorderTraversal(TreeNode* root) {
    
    
        if(root == nullptr) return {
    
    };
        inorder(root);
        return ans;
    }
    void inorder(TreeNode* root) {
    
    
        if(root == nullptr) {
    
    
            return;
        }
        inorder(root -> left);
        ans.push_back(root ->val);
        inorder(root -> right);
    }
};

Post-order traversal

Leetcode - 145

class Solution {
    
    
public:
    vector<int> ans;
    vector<int> postorderTraversal(TreeNode* root) {
    
    
        if(root == nullptr) return {
    
    };
        postorder(root);
        return ans;
    }
    void postorder(TreeNode* root) {
    
    
        if(root == nullptr) {
    
    
            return;
        }
        postorder(root -> left);
        postorder(root -> right);
        ans.push_back(root ->val);
    }
};

Non-recursive

The stack can be used to simulate recursive implementation. In fact, it reflects the idea of ​​dfs. But the difficulty is much greater than recursion. The process must be analyzed and then expressed with the help of the stack. There is no obvious rule.

Preorder traversal

In the iterative algorithm, the idea evolved into a node A, it should be accessed immediately.

Because each subtree visits its root node first. For the left and right subtrees of a node, the root must also be visited first.

In the two subtrees of A, after traversing the left subtree, traverse the right subtree again.

Therefore, after visiting the root node, before traversing the left subtree, push the right subtree onto the stack.

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

In-order traversal

At each node A, because the root access is in the middle, A is pushed onto the stack. Then traverse the left subtree, then visit A, and finally traverse the right subtree.
After accessing A, A can be popped from the stack. Because A and its left subtree have been visited.
See notes for specific ideas

class Solution {
    
    
    public:
    vector<int> inorderTraversal(TreeNode* root) {
    
    
        if(root == nullptr) {
    
    
            return {
    
    };
        }
        stack<TreeNode*> s;
        vector<int> ans;
        TreeNode* cur = root;
        //一开始cur不入栈防止入栈两次
        while(cur || !s.empty()) {
    
    
            while(cur) {
    
    
                //将所有左子树入栈
                s.push(cur);
                cur = cur -> left;
            }
            //如果已经到了最左结点,将其入数组
            cur = s.top();
            s.pop();
            ans.push_back(cur -> val);
            //在根结点入数组的同时将根结点出栈,寻找根结点右边是否还有右子树
            //如果发现就能继续递归的过程,
            cur = cur -> right;
        }
        return ans;
    }
};

Post-order traversal

Traversal sequence after sequence is about root **, and through the front left and right reversed order traversal subtree stack order , we can get root right-left sequence,
and then get the entire array can be reversed to get around the root . This is the best to understand, there is another solution that can refer to the solution of the big guy

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

Guess you like

Origin blog.csdn.net/qq_42883222/article/details/114702722