题目描述
LeetCode传送门:105. 从前序与中序遍历序列构造二叉树
题目分析
观察前序和中序遍历序列可以知道前序遍历序列的第一个元素为该树的根节点,而中序遍历序列中根结点的左边为根结点左子树的中序遍历序列,右边为中序遍历序列。而根据两序列根结点的位置,又可确定前序序列中左右子树的前序遍历序列,从而递归求得这棵二叉🌲。
根据分析可知,需要7个变量:确定中序序列根结点变量i,前序遍历和中序遍历子树初始位置ini_pnum、ini_inum,中序遍历子树结束位置inum,左右子树规模left_len、right_len,创建二叉树的结点tr.
下面以题目样例为例,进行分析:
前序遍历序列:preorder = [3, 9, 20, 15, 7]
中序遍历序列:inorder = [9, 3, 15, 20, 7]
- 找到根结点3,并确定根结点在中序遍历序列中的位置inorder[1].
- 左边{9}为左子树序列,右边{15, 20, 7}为右子树序列。同时左右子树在前序遍历序列中的位置也可确定
- 先看左子树,由于此时中序遍历左子树初始位置等于结束位置,代表该左子树仅一个元素,则仅需创建结点后返回即可。
- 再看右子树,右子树的中序遍历序列为{15, 20, 7},前序遍历序列为{20, 15, 7},由此确定右子树根结点为20,下面重复前面所述步骤即可,结束递归的条件为中序遍历左子树初始位置等于结束位置(即子树仅有一个元素)
代码示例
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
struct TreeNode* CreateNode(int val) //构造树结点
{
struct TreeNode* p = (struct TreeNode*)malloc(sizeof(struct TreeNode));
p->val = val;
p->right = NULL;
p->left = NULL;
return p;
}
/*ini_pnum、ini_inum为该轮构建前序遍历和中序遍历序列数组的起始位置*/
struct TreeNode* Build(int *preorder, int ini_pnum, int *inorder, int ini_inum, int inum){
struct TreeNode* tr = CreateNode(preorder[ini_pnum]); //构造树结点
int i;
if(ini_inum != inum){ //若序列中只有一个元素则直接返回
for(i = ini_inum; i <= inum ; i++) //寻找中序遍历序列中的根结点所在位置
if(inorder[i] == preorder[ini_pnum]) //找到则跳出循环
break;
int left_len = i - ini_inum; //左子树规模
int right_len = inum - i; //右子树规模
if(left_len) //若左子树规模为0(即根结点只有右子树)则跳过
tr->left = Build(preorder, ini_pnum+1, inorder, ini_inum, i-1); //递归构造左子树
if(right_len) //若右子树规模为0(即根结点只有左子树)则跳过
tr->right = Build(preorder, ini_pnum+left_len+1, inorder, i+1, inum); //递归构造右子树
}
return tr;
}
/*preorder和inorder分别为前序遍历序列数组和中序遍历序列数组,pnum和inum分别为两数组的规模*/
struct TreeNode* buildTree(int* preorder, int pnum, int* inorder, int inum){
if(!pnum && !inum) //若两序列为空,则直接返回空节点
return NULL;
return Build(preorder, 0, inorder, 0, inum - 1); //原inum值为数组规模,减1使其变为最大下标
}