Interviewer: you don't even know how to restore the binary tree?

Posted by jarriola on Tue, 08 Feb 2022 10:29:10 +0100

Recover the binary tree according to traversal

In the knowledge of binary tree, finding or traversing binary tree is a very important knowledge point. Because the author only paid attention to the traversal process of binary tree before, but ignored the importance of the inverse process of recovering binary tree from traversal. When I saw an algorithm problem one day, I found that there was still an inverse process in the former, middle and later traversal! So I opened the corresponding books and wrote this note in combination with the algorithm title
Theorem 1: the preorder traversal and inorder traversal of any binary tree can uniquely determine the binary tree

In fact, this may be a little confusing. Let me explain my idea. The middle order traversal order of binary tree is left root right, and the first order traversal order is root left right. In this order, the first node of the first order traversal must be the root node, the root node of the middle order traversal must be in the middle, and the left and right sides are the middle order traversal of the left and right subtrees respectively, According to the node distribution at the middle order traversal root node position, a binary tree can be restored by recursion. The recursive steps of each step can be
1 , first before look for reach in order Times calendar root section spot of position Set 2 , in order Times calendar root section spot Left edge of ( common k individual ) number according to by root section spot Left son tree of in order Times calendar 3 , right edge of ( n − k − 1 individual ) number according to by root section spot right son tree of in order Times calendar 1. First, find the location of the middle order traversal root node \ \ 2. The data on the left (K in total) of the middle order traversal root node is the middle order traversal of the left subtree of the root node \ \ 3. The data on the right (n-k-1) is the middle order traversal of the right subtree of the root node 1. First, find the location of the middle order traversal root node. 2. The data on the left (k in total) of the middle order traversal root node is the middle order traversal of the left subtree of the root node. 3. The data on the right (n − k − 1) is the middle order traversal of the right subtree of the root node
Split the problem into subtrees, and the subtree is split into subtrees. Recurse layer by layer and backtrack in turn until the final result is returned. Here you can draw a diagram to understand the allocation process. For example, the middle order traversal and first order traversal of a tree are respectively:

See code:

typedef struct node{
    char data;
    node* left;
    node* right;
} BTNode; //The node data organization type of binary tree adopts the binary chain storage structure, and the binary tree is also restored from post order traversal and middle order traversal
BTNode* CreateBT1(char* pre,char *in,int n){
    BTNode* b;
    char *p;
    int k;
    if(n<=0)
        return nullptr;
    b = (BTNode*)malloc(sizeof(BTNode));
    b->data = *pre;
    for(p = in;p<in+n;p++){
        if(*p==*pre)
            break;
    }
    k = p - in;
    b->left = CreateBT1(pre+1,in,k);
    b->right = CreateBT1(pre+k+1,p+1,n-k-1);
}
//Here, it is assumed that the element stored in the binary tree is char

leedCode also has the same algorithm problem and the same idea. Its title is

According to the preorder traversal and inorder traversal of a tree, a binary tree is constructed.

be careful:
You can assume that there are no duplicate elements in the tree.

For example, give

preorder = [3,9,20,15,7]
Middle order traversal inorder = [9,3,15,20,7]
Return the following binary tree:

3
/ \
9 20
/ \
15 7
Source: LeetCode
Link: https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal
The copyright belongs to Lingkou network. For commercial reprint, please contact the official authorization, and for non-commercial reprint, please indicate the source.

Code (c + + implementation)

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        TreeNode* roots = nullptr;
        if(preorder.size()!=inorder.size())  //Ensure that the array length of the incoming pre traversal and subsequent traversal is the same
            return roots;
        if(preorder.size()<=0) //Ensure that the passed in array length is valid
            return roots;
        roots = buildTree(preorder,inorder,0,preorder.size()-1,0,inorder.size()-1); //The values of roots are assigned recursively
        return roots;
    }
    TreeNode* buildTree(vector<int>& preorder,vector<int>& inorder,int pre_start,int pre_end,int in_start,int in_end){
        TreeNode* roots = new TreeNode(); //Initialize the node of a tree
        roots->val = preorder[pre_start]; //The first value of the first traversal array is the value of the root node
        int k = in_start; //Starting from the starting point of the middle order traversal, find the location of the root node in the middle order traversal
        for(;k<in_end;k++){
            if(preorder[pre_start]==inorder[k])
                break; //Find the location of the root node in the middle order traversal
        } 
        if(pre_end==pre_start){ //If the start position and end position are the same, there is only one node in the preorder array in the description, and there is no need to assign values to the left and right subtrees
            return roots;
        }else{  //There are three situations          
            if(k==in_start){ //If this root node has no left subtree, the root node is at the front of the middle order traversal
                roots->right = buildTree(preorder,inorder,pre_start+1,pre_end,k+1,in_end);
            }else if(k==in_end){ //This root node has no right subtree, and the root node appears at the end of the middle order traversal
                roots->left = buildTree(preorder,inorder,pre_start+1,pre_end,in_start,k-1);
            }else{ //There are both left subtree and right subtree
                roots->left = buildTree(preorder,inorder,pre_start+1,pre_start+k-in_start,in_start,k-1);
                roots->right = buildTree(preorder,inorder,pre_start+k-in_start+1,pre_end,k+1,in_end);
            }
        }
        return roots;
    }
};

Java implementation

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        TreeNode roots = new TreeNode();
        if(preorder.length!=inorder.length)
            return roots;
        if(preorder.length<=0)
            return roots;
        roots = buildTree(preorder,inorder,0,(preorder.length-1),0,(inorder.length-1));
        return roots;
    }

    private TreeNode buildTree(int[] preorder,int[] inorder,int pre_start,int pre_end,int in_start,int in_end){
        TreeNode roots = new TreeNode();
        roots.val = preorder[pre_start];
        int k = in_start;
        for(;k<in_end;k++){
            if(preorder[pre_start]==inorder[k])
                break;
        }
        if(pre_start==pre_end)
            return roots;
        else{
            if(k==in_start)
                roots.right = buildTree(preorder,inorder,pre_start+1,pre_end,k+1,in_end);
            else if(k==in_end)
                roots.left = buildTree(preorder,inorder,pre_start+1,pre_end,in_start,k-1);
            else{
                roots.left = buildTree(preorder,inorder,pre_start+1,pre_start+k-in_start,in_start,k-1);
                roots.right = buildTree(preorder,inorder,pre_start+k-in_start+1,pre_end,k+1,in_end);
            }
        }    
        return roots;
    }
}

Theorem 2: the middle order traversal and post order traversal of any binary tree can uniquely determine the binary tree

After understanding the above idea of recovering a binary tree from preorder traversal and middle order traversal, the same idea is used to recover a binary tree from post order traversal and middle order traversal, but the order will change a little, because the root node of post order traversal is at the end. At this time, we need to start from the end of post order traversal to find the location of the root node in middle order traversal, If a binary tree is only understood as the root node and the left and right subtrees, its post order traversal can be understood as the post order traversal of the left subtree + the post order traversal of the right subtree + the root node, and the middle order traversal, that is, the above-mentioned middle order traversal of the left subtree + the root node + the middle order traversal of the right subtree. In this way, the corresponding part can be split, Another subproblem with simplified thinking logic is obtained!, According to this idea, you can also draw the flow chart of the tree above through traversal and recovery in the middle and later order

Middle order traversal: DBEAFCG

Post order traversal: DEBFGCA

BTNode* CreateBT2(char *post,char *in,int n){
    BTNode *b;
    char r,*p;
    int k;
    r = *(post+n-1);
    b = (BTNode*)malloc(sizeof(BTNode));
    b->data = r;
    for(p = in;p<in+n;p++){
        if(*p==r)
            break;
    }
    k = p-in;
    b->left = CreateBT2(post,in,k);
    b->right = CreateBT2(post+k,p+1,n-k-1);
}

Topics: Algorithm data structure Binary tree recursion