7, Binary tree: a unified iterative method of binary tree

        At this time, we are Binary tree: as soon as you enter recursion, it is as deep as the sea. Since then, offer is a passer-by   (opens new window) Recursive method is used to traverse the front, middle and back order of binary tree.

        stay Binary tree: I heard that recursion can do, stack can also do!   (opens new window) The stack is used to realize the iterative traversal (non recursive) of the middle order before and after the binary tree. After that, we found that the style of the iterative method is not so unified. In addition to the correlation between the first order and the second order, the middle order is completely another style. It is traversed by stack and pointer.

        Students who have practiced will also find that it is difficult to write unified code by using the iterative method to realize the first middle then order traversal. Unlike the recursive method, one of the traversal methods is realized, and the other two only need to change the node order slightly.

        In fact, for the three traversal methods, the use of iterative method can write unified style code! Here comes the play. Next, let's introduce the unified writing method. Let's take middle order traversal as an example Binary tree: I heard that recursion can do, stack can also do!   (opens new window) It is mentioned in that if the stack is used, the inconsistency between the access node (traversal node) and the processing node (putting elements into the result set) cannot be solved at the same time.

        Then we put the accessed nodes into the stack and the nodes to be processed into the stack, but we need to mark them. How to mark is to put a null pointer as a mark after the node to be processed is put into the stack.   This method can also be called marking method.

1, Order traversal in iterative method

The middle order traversal code is as follows: (detailed comments)

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> st;
        if (root != NULL) st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top();
            if (node != NULL) {
                st.pop(); // Pop up the node to avoid repeated operations. Next, add the right, middle and left nodes to the stack
                if (node->right) st.push(node->right);  // Add the right node (empty nodes are not stacked)

                st.push(node);                          // Adding nodes
                st.push(NULL); // The node in has been accessed but has not been processed. Add an empty node as a tag.

                if (node->left) st.push(node->left);    // Add left node (empty nodes are not stacked)
            } else { // Only when an empty node is encountered, the next node is put into the result set
                st.pop();           // Pop up empty node
                node = st.top();    // Retrieve the elements in the stack
                st.pop();
                result.push_back(node->val); // Add to result set
            }
        }
        return result;
    }
};

The code is a little abstract. Let's take a look at the animation (medium order traversal):

In animation, the result array is the final result set. It can be seen that we directly add the accessed node to the stack, but if it is a processing node, an empty node will be placed later. In this way, the next node will be put into the result set only when the empty node pops up.

At this point, let's look at the preamble traversal code.


2, Iterative preorder traversal

The pre order traversal code of the iterative method is as follows: (note that we only change the order of two lines of code compared with the middle order traversal)

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> st;
        if (root != NULL) st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top();
            if (node != NULL) {
                st.pop();
                if (node->right) st.push(node->right);  // right
                if (node->left) st.push(node->left);    // Left
                st.push(node);                          // in
                st.push(NULL);
            } else {
                st.pop();
                node = st.top();
                st.pop();
                result.push_back(node->val);
            }
        }
        return result;
    }
};

3, Sequential traversal of iterative method

The subsequent traversal code is as follows: (note that we only change the order of two lines of code compared with the middle order traversal)

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> st;
        if (root != NULL) st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top();
            if (node != NULL) {
                st.pop();
                st.push(node);                          // in
                st.push(NULL);

                if (node->right) st.push(node->right);  // right
                if (node->left) st.push(node->left);    // Left

            } else {
                st.pop();
                node = st.top();
                st.pop();
                result.push_back(node->val);
            }
        }
        return result;
    }
};

4, Summary

At this time, we have written a unified style of iterative method, so we don't have to worry about the situation that the previous order can't be written and the middle order can't be written. However, the unified style iterative method is not easy to understand, and it is difficult to write it directly in the interview.

Therefore, according to your personal preferences, we choose a recursive and iterative method that is easy to understand for the first, middle and last traversal of binary tree.

Tags: Python Algorithm data structure

Posted on Sat, 11 Sep 2021 14:50:22 -0400 by jordz