前序遍历序列:根左右,序列第一个数字一定是根节点值。其后分别是左子树序列和右子树序列。
中序遍历序列:左根右,根节点在中间,根节点左侧是左子树,根节点右侧是右子树。
后序遍历序列:左右根,根节点在最后。
以下两种方式其实是一种思想:先从前序遍历序列第一个位置找到根节点值,创建树节点,通过这个值再在中序遍历序列中找到根节点所在位置。然后分出根节点左右子树的前序和中序序列,进行递归创建root节点。
二叉树中所有节点都可以看成子树的根节点。
指针用法:
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
TreeNode* ConstructCore(int* startPre, int* endPre, int* startIn, int* endIn){
//前序遍历序列的第一个数字是根节点的值
int rootValue = startPre[0];
//创建根节点
TreeNode* root = new TreeNode(rootValue);
//root->val = rootValue;
//root->left = root->right = NULL;
//判断是不是只有一个根节点
if (startPre == endPre){
if (startIn == endIn && *startIn == *startPre) return root;
//else throw std::exception("Invalid input.");
}
//在中序遍历中找到根节点值的位置
int* rootIn = startIn;
while (rootIn <= endIn && *rootIn != rootValue) ++rootIn;
//if (rootIn == endIn+1 && *rootIn != rootValue) throw std::exception("Invalid input.");
//找到左子树长度
int leftlength = rootIn - startIn;
//前序遍历中左子树的结束位置
int* leftPreend = startPre + leftlength;
if (leftlength > 0){
//构建左子树
root->left = ConstructCore(startPre+1,leftPreend, startIn, rootIn-1);
}
if (leftlength < endPre - startPre){
//构建右子树
root->right = ConstructCore(leftPreend+1, endPre, rootIn+1, endIn);
}
}
TreeNode* reConstructBinaryTree(int* pre, int* vin, int length) {
if (pre == nullptr || vim == nullptr || length == 0) return nullptr;
return ConstructCore(pre, pre+length-1, vin, vin+length-1);
}
vector用法1(引用方式,效率):
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* reConstructBinaryTree(vector<int>& pre, vector<int>& vin) {
int n1 = pre.size();
int n2 = vin.size();
if (n1 != n2 || 0 == n1 || 0 == n2) {
return NULL;
}
return __buildTree(pre, 0, n1 - 1, vin, 0, n2 - 1);
}
TreeNode* __buildTree(vector<int>& preorder, int pre_start, int pre_end, vector<int>& inorder, int in_start, int in_end) {
if (pre_start > pre_end) {
return NULL;
}
//创建根节点
TreeNode* root = new TreeNode(preorder[pre_start]);
//找到根节点在中序遍历序列中的位置,求得左子树长度
int length = 0;
for (int i = in_start; i != in_end; ++i) {
if (preorder[pre_start] == inorder[i]) {
break;
}
++length;
}
if (length > 0) { // 左子树存在,递归左子树
root->left = __buildTree(preorder, pre_start + 1, pre_start + length, inorder, in_start, in_start + length - 1);
}
if (pre_start + length < pre_end) {
root->right = __buildTree(preorder, pre_start + length + 1, pre_end, inorder, in_start + length + 1, in_end);
}
return root;
}
};
vector方法2:
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
struct TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> in) {
int inlen=in.size();
if(inlen==0)
return NULL;
vector<int> left_pre,right_pre,left_in,right_in;
//创建根节点,根节点肯定是前序遍历的第一个数
TreeNode* head=new TreeNode(pre[0]);
//找到中序遍历根节点所在位置,存放于变量gen中
int gen=0;
for(int i=0;i<inlen;i++)
{
if (in[i]==pre[0])
{
gen=i;
break;
}
}
//对于中序遍历,根节点左边的节点位于二叉树的左边,根节点右边的节点位于二叉树的右边
//利用上述这点,对二叉树节点进行归并
for(int i=0;i<gen;i++)
{
left_in.push_back(in[i]);
left_pre.push_back(pre[i+1]);//前序第一个为根节点
}
for(int i=gen+1;i<inlen;i++)
{
right_in.push_back(in[i]);
right_pre.push_back(pre[i]);
}
//和shell排序的思想类似,取出前序和中序遍历根节点左边和右边的子树
//递归,再对其进行上述所有步骤,即再区分子树的左、右子子数,直到叶节点
head->left=reConstructBinaryTree(left_pre,left_in);
head->right=reConstructBinaryTree(right_pre,right_in);
return head;
}
};