Hand torn binary tree traversal (pre order + middle order + post order recursive + non recursive code implementation + example)

Forward citation

Just finished writing the blog of tearing the smallest pile by hand, I thought, do you have to write a binary tree traversal? Ha ha, because I wrote it some time ago and it took a lot of time to understand at that time, so now it takes about 5 minutes to tear three traversals by hand, and the traversal of the front, middle and back order will be all AC at once. After writing this article, I'll go to dinner and get into the next step Let's face it

Introduction to binary tree traversal

Binary tree is really classic. It can't be classic anymore. You must master its three non recursive traversals skillfully! The interview must be very often. I won't test you. Otherwise, it's too retarded. Ha ha

Before traversing a binary tree, we need to find out what is the pre order, what is the middle order and what is the post order. We will use this figure later, and we won't talk about it here
Of course, traversal is not only used in binary search tree, any tree can be traversed, but there are some other properties for the first, middle and last traversal of binary search tree, which will be discussed later

1. Preorder traversal of binary tree

Before we talk about code implementation, we give the results of the above preamble


We can understand that we prefer to output the value first, then move the left node, and finally move the right node. Every time we move, we will act in this order

1. Binary tree preorder traversal code (recursion)

As the most classic recursive implementation, the recursive code is as follows

class Solution {
public:
    void preorder_visit(TreeNode* root,vector<int>& ret)
    {
        if(!root)   return;
        ret.emplace_back(root->val);
        preorder_visit(root->left,ret);
        preorder_visit(root->right,ret);
    }

    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> ret;
        preorder_visit(root,ret);
        return ret;
    }
};

2. Binary tree preorder traversal code (non recursive)

I don't think it's easy to talk about non recursion
I write code in an abstract representation
I think it's the preamble. Whenever we access a node, we immediately put it into the array
When traversing to the far left, check whether there is a node on the right. If there is no re-entry cycle, it doesn't matter that the current pointer is equal to nullptr to enter the next cycle

Let's understand it in combination with the code

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        TreeNode* ptr = root; 
        stack<TreeNode*> stack;
        vector<int> ret;

        while(ptr || stack.size())
        {
            while(ptr)
            {
                stack.emplace(ptr);        //Put pointer
                ret.emplace_back(ptr->val);//Put it now
                ptr = ptr->left;		 
            }
            
            ptr = stack.top()->right; //Access the right pointer at the top
            stack.pop();			  //If it has been used, pop it directly
        }
        return ret;
    }
};

2. Order traversal in binary tree

Similarly, for your convenience, I'd better take some time to do the middle order traversal results myself


If the middle order traversal is performed, we'd better directly look at the following code. Let's understand it together with this figure

1. Binary tree sequence traversal code (recursive)

Directly to the code

class Solution {
public:
    void inorder_visit(TreeNode* root,vector<int>& ret)
    {
        if(!root)   return;
        inorder_visit(root->left,ret);
        ret.emplace_back(root->val);
        inorder_visit(root->right,ret);
    }

    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> ret;

        inorder_visit(root,ret);
        return ret;
    }
};

2. Ordinal traversal code in binary tree (non recursive)

I'd better take some time to write this part
My understanding is that we still write with recursive code
First, instead of pushing numbers when encountering nodes, push numbers from the stack in recursive order. If it comes out of the stack, push again, and then ptr is the same. The order of pushing numbers does not change from stack. Top() - > right

The code is implemented as follows

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        TreeNode* ptr = root; 
        stack<TreeNode*> stack;
        vector<int> ret;

        while(ptr || stack.size())
        {
            while(ptr)
            {
                stack.emplace(ptr); //Storage pointer
                ptr = ptr->left;  
            }
            
            ptr = stack.top();   //Inverted pointer
            stack.pop();		 //Yes
            ret.emplace_back(ptr->val); // Put the values back in, in recursive order
            ptr = ptr->right;			// Look at the right pointer
        }
        return ret;
    }
};

3. Postorder traversal of binary tree

As usual, put the post order traversal result graph

1. Binary tree postorder traversal code (recursion)

Put the code directly

class Solution {
public:
    void postorder_visit(TreeNode* root,vector<int>& ret)
    {
        if(!root)   return;
        postorder_visit(root->left,ret);
        postorder_visit(root->right,ret);
        ret.emplace_back(root->val);
    }

    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> ret;
        postorder_visit(root,ret);

        return ret;
    }
};

2. Binary tree postorder traversal code (non recursive)

The post order is different from the pre order and the middle order. It is a little difficult, but it is only a little different, because we need to wait until whether the current node has been exhausted
I understand it this way. It is necessary to require the right node to be pushed into the array in front of the current node. If the previous right pointer is not a pre pointer, it means that the right or nullptr. If it is a null pointer, we can directly push into the array, because it means that the current pointer is the last one
The code I understand is written in this way. The following is not very easy to understand. I hope you will spend more time understanding the following code

Then the last one will put the code directly

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        TreeNode* ptr = root,*pre = nullptr; \\pre The previous pointer record is pushed into the array 
        stack<TreeNode*> stack;
        vector<int> ret;

        while(ptr || stack.size())
        {
            while(ptr)
            {
                stack.emplace(ptr);
                ptr = ptr->left;
            }
            
            ptr = stack.top();
            if(!ptr->right || ptr->right == pre) //If the right pointer is empty or the right has been pushed, it can be pushed directly
            {
                ret.emplace_back(ptr->val);
                pre = ptr;
                stack.pop();
                ptr = nullptr;
            }
            else    ptr = ptr->right;
        }
        return ret;
    }
};

Binary tree traversal example

Now let's put three classic force deduction questions in the first, middle and last order. You can also verify whether your code is correct through these three questions. Finally, I've finished writing. Now I'm playing DK in EDG. I have to write it quickly and go back to my bedroom to watch the game. I'm too excited to write it here first

144. Preorder traversal of binary tree
94. Middle order traversal of binary tree
145. Post order traversal of binary tree

Love 6 record blog 144. Preorder traversal of binary tree (iterative recursive Morris)
Love 6 record blog 94. Middle order traversal of binary tree
Love 6 record blog 145. Post order traversal of binary tree (divine Morris)

Tags: Algorithm data structure

Posted on Sat, 06 Nov 2021 18:16:07 -0400 by banzaimonkey