Use any two binary tree traversal reconstruction

Foreword

Learn how to use the pre-order traversal and traversal sequence to rebuild the binary tree, I was thinking about whether or not to know any two traversal, binary tree can be reconstructed out of it? Careful study one night, is really the case.

Find the law

Look at the three kinds of traversal

struct Tree{
    int val;
    Tree *left;
    Tree *right;
};

void printTree(Tree *node,int mode){
    if(node!=nullptr){
        switch(mode){
            case 1:
                cout<<node->val<<",";
                printTree(node->left, mode);
                printTree(node->right, mode);
                break;
            case 2:
                printTree(node->left, mode);
                cout<<node->val<<",";
                printTree(node->right, mode);
                break;
            case 3:
                printTree(node->left, mode);
                printTree(node->right, mode);
                cout<<node->val<<",";
                break;
            default:
                break;
        }
    }
}

Code not say, understand, before the corresponding 1,2,3 respectively, in postorder traversal.

The first and most important rule is, remove the root node data, each function call is the first output of all data left subtree, and then output the data right subtree. This law has nothing to do with recursion, I believe it should be easy to find.

//cout<<node->val<<",";
printTree(node->left, mode);
//cout<<node->val<<",";
printTree(node->right, mode);
//cout<<node->val<<",";

Besides the second rule, the output of each of the preorder traversal of a root node must be the data, on the contrary postorder traversal, the last one is the output data from each root node.

Preorder traversal and preorder

Preorder traversal: 3,0,1,2,6,5,4,8,7,9
preorder: 0,1,2,3,4,5,6,7,8,9

According to the law preorder traversal, we can know the root node 3. We will root through preorder divided into left subtree and right subtree.

Preorder: [0, 1] [3] [4,5,6,7,8,9]
root: 3
left subtree: 0,1,2
right subtree: 4,5,6 , 7,8,9

At this time, knowing the number of left and right subtree, preorder traversal may be also divided into left and right subtree subtree

Preorder traversal: [3] [0,1,2] [6,5,4,8,7,9]
root: 3
left subtree: 0,1,2
right subtree: 6,5,4 , 8,7,9

Generating new left subtree and the right subtree of the above operation is repeated until each node as the root node through.

Look at the implementation code:

//pre:前序遍历
//mid:中序遍历
//length:数组长度
Tree* Fun1(const int *pre, const int *mid,const int length) {
	//当空指针或者数组长度为0时返回
	if (pre == NULL || mid == NULL || length <= 0) 
	    return NULL;

	//建立根节点
	Tree *head = new Tree();
	head->value=pre[0];
	head->left=head->right=NULL;

	//找到中序遍历中根节点所在位置
	int index = 0;
	while (index<length) {
		if (head->value == mid[index])
			break;
		++index;
	}

	//划分左子树
	head->left = Fun1(pre + 1, mid, index);
	//划分右子树
	head->right = Fun1(pre + index +1, mid + index + 1, length - index - 1);

	return head;
}

Preorder and postorder

Principle is basically the same as above, except that the root node into an array Finally, here is not to explain, I hope you can on her own.

//mid:中序遍历
//back:后序遍历
//length:数组长度
Tree* Fun2(const int *mid,const int *back,const int length){
    //当空指针或者数组长度为0时返回
    if(back==NULL||mid==NULL||length<=0)
        return NULL;
    
    //建立根节点
    Tree *head=new Tree();
    head->val=back[length-1];
    head->left=head->right=NULL;
    
    //找到中序遍历中根节点所在位置
    int index=0;
    while(index<length){
        if(head->val==mid[index]){
            break;
        }
        ++index;
    }
    
    //划分左子树
    head->left=Fun2(mid,back,index);
    //划分右子树
    head->right=Fun2(mid+index+1, back+index, length-index-1);
    
    return head;
}

Preorder traversal and postorder

Preorder traversal: 3,0,1,2,6,5,4,8,7,9
post-order traversal: 2,1,0,4,5,7,9,8,6,3

Read the previous derivation, I believe that to find the root of Data 3 for everybody a little difficult at all. The difficulty is how to separate the left subtree and right subtree.
A closer look reveals a very interesting law, the first is always the last one the same (after all, the root data) and post-order traversal of traversal of the preamble.

Preorder traversal: [3], 0,1,2,6,5,4,8,7,9
postorder traversal: 2,1,0,4,5,7,9,8,6, [3]

Removing the root data:

Preorder traversal (left + right subtree subtree): 0,1,2,6,5,4,8,7,9
postorder (left + right subtree subtree): 2,1,0,4 , 5,7,9,8,6

Because the left subtree first, so this time before the preorder traversal of the first necessity is the root of the left subtree, but we also know that the root of the left subtree order traversal of the last bit of data in the left subtree , we mark this:

Preorder traversal (left + right subtree subtree): [0], 1, 2 + 6,5,4,8,7,9
postorder (left + right subtree subtree): 2,1, [ 0] + 4,5,7,9,8,6

In this way it can easily be left subtree and right subtree distinguished here. And then further divided.
This all? Of course not, in fact, there's a small trap, just to the left subtree distinguish us as an example:

Preorder traversal: [0], 1,2
postorder traversal: 2,1, [0]

According to the above method we can know at this time to distinguish between sub-tree:

Preorder traversal (left + right subtree subtree): [1], 2 + NULL
postorder (left + right subtree subtree): 2, [1] + NULL

However, this case [2] is not a left subtree (1,2 root greater than 0), but the right subtree.
This situation is due to the left and right subtrees wherein a blank, at this time the need for simple determination (large small left and right).
OK, can the code:

//pre:前序遍历
//back:后序遍历
//length:数组长度
Tree* Fun3(const int *pre,const int *back,const int length){
    //当空指针或者数组长度为0时返回
    if(pre==NULL||back==NULL||length<=0)
        return NULL;
    
    //建立根节点
	Tree *head = new Tree();
	head->value=pre[0];
	head->left=head->right=NULL;
    
    //数组长度为1时,直接返回,因为没有子节点了
    if(length>1){
        //找到左右子树的分界点
        int index=0;
        while(index<length){
            if(pre[1]==back[index]){
                break;
            }
            ++index;
        }
        
        //判断是否是唯一子树
        if(index==length-2){
            //唯一子树需要判断为左子树还是右子树
            if(back[0]<head->val){
                head->left=Fun3(pre+1,back,index+1);
            }else{
                head->right=Fun3(pre+1, back, index+1);
            }
        }else{
            //左右子树均存在时,左边的为左子树,右边的为右子树
            head->left=Fun3(pre+1,back,index+1);
            head->right=Fun3(pre+index+2, back+index+1, length-index-2);
        }
    }
    
    return head;
}
Published 63 original articles · won praise 73 · views 70000 +

Guess you like

Origin blog.csdn.net/jjwwwww/article/details/85848891