题目描述
输入某二叉树的前序遍历和中序遍历的序列,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
问题思路
1、在以往的数据结构课程中,已知二叉树的前序遍历和中序遍历可以得到二叉树的后序遍历并画出该二叉树,这是可以用来出简答题的。本题目要求已知前序和中序序列,返回二叉链表存储的二叉树结构。
2、考察相关知识点:对二叉树性质的了解,前中后三种遍历的了解,C++中
v
e
c
t
o
r
vector
vector容器的使用方法和相关查找(
f
i
n
d
find
find),复制(
c
o
p
y
copy
copy)算法。
3、二叉树的前序遍历序列的第一个元素即二叉树的根结点,由于序列中不存在重复的元素,即在二叉树中序遍历序列中的该元素值为该二叉树的根结点,该结点的左边序列为二叉树的左子树的结点值,该结点右边的元素为该二叉树右子树的结点值。则取出先序遍历序列中左子树的序列和中序遍历序列中的左子树序列,取出先序遍历中右子树的序列和中序遍历中右子树的序列,分别进行函数递归,进而返回整个二叉树。
相关代码
class Solution {
public:
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
if(pre.empty() || vin.empty())
return NULL;
TreeNode* head = new TreeNode(pre[0]); //创建根结点 括号中赋值
int pos = 0;
for(;pos < pre.size();pos++)
{
if(vin[pos] == pre[0])
{
break;
}
}
//定义4个容器 并赋值
vector<int> pre_left(pre.begin() + 1,pre.begin() + pos + 1);
vector<int> pre_right(pre.begin() + 1 + pos,pre.end());
vector<int> vin_left(vin.begin(),vin.begin() + pos);
vector<int> vin_right(vin.begin() + 1 + pos,vin.end());
// 进行函数递归操作
head->left = reConstructBinaryTree(pre_left,vin_left);
head->right = reConstructBinaryTree(pre_right,vin_right);
//返回二叉树头结点
return head;
}
};
知识点
1、vector类为容器类(STL),即动态数组
容器定义
vector<int> v;
尾部插入元素
v.push_back()
尾部删除元素
v.pop_back()
容器中元素的个数
v.size()
容器判空
v.empty()
遍历容器 用迭代器指向容器的开始位置,而且遍历的序列为左闭右开。
vector<int>::iterator it = v.begin();
for(;it != v.end();it++)
cout << *it << endl;
定义容器并初始化容量为10的动态数组;
vector<int> v2(10);
初始化容器v2 并将v容器中的元素赋值给v2。
vector<int> v2(v.begin(),v.end());
2、用new方法创建结点,在括号中直接赋值
TreeNode* head = new TreeNode(pre[0]); //创建根结点 括号中赋值
等同于C语言中下列代码
TreeNode* head = (TreeNode*)malloc(sizeof(TreeNode));
head->val = pre[0];
new方法开辟n个结点,后面是 [ ]
int* arr = new int[5];//开辟容量为5的整型数组
3、C++中定义了很多算法,在头文件#include<algorithm>中,例如复制(copy)函数,本题目除了vector<int> v2(v.begin(),v.end());
这样复制之外,下列算法也可以
copy(v.begin(),v.end(),v2.begin());
即上述给pre_left、pre_right、vin_left、vin_right 分配元素时,也可以使用如下代码
//提前定义好4个容器并且分配容量
vector<int> pre_left(pos);
vector<int> pre_right(pre.size() - pos - 1);
vector<int> vin_left(pos);
vector<int> vin_right(vin.size() - pos - 1);
//执行copy函数
copy(pre.begin() + 1,pre.begin() + pos + 1,pre_left.begin());
copy(pre.begin() + 1 + pos,pre.end(),pre_right.begin());
copy(vin.begin(),vin.begin() + pos,vin_left.begin());
copy(vin.begin() + 1 + pos,vin.end(),vin_right.begin());
find函数利用底层元素的等于操作符,对指定范围内的元素与输入值进行比较。当匹配时,结束搜索,返回该元素的迭代器。(注:find函数与本题无关)
vector<int> vecInt;
vecInt.push_back(1);
vecInt.push_back(3);
vecInt.push_back(5);
vecInt.push_back(7);
vecInt.push_back(9);
vector<int>::iterator it = find(vecInt.begin(), vecInt.end(), 5);//*it == 5
以上通过直接拷贝的方法,就剩去了4次手动循环带来的代码的冗余和运行时间的增多。
不使用C++自带拷贝函数的代码
class Solution {
public:
TreeNode* reConstructBinaryTree(vector<int> per,vector<int> vin) {
if(per.size()<=0||vin.size()<=0)
return NULL;
int value=per[0];
TreeNode* node=new TreeNode(value);
vector<int>vin_left;vector<int>vin_right;
vector<int>::iterator ite_t=vin.begin();
while(*ite_t!=value)
{
vin_left.push_back(*ite_t);
++ite_t;
}
++ite_t;
while(ite_t!=vin.end())
{
vin_right.push_back(*ite_t);
++ite_t;
}
vector<int>per_left; vector<int>per_right;
int i=1;
for(;i<=vin_left.size();++i)
per_left.push_back(per[i]);
for(;i<per.size();++i)
per_right.push_back(per[i]);
node->left=reConstructBinaryTree(per_left,vin_left);
node->right=reConstructBinaryTree(per_right,vin_right);
return node;
}
};
该方法就是使用使用4次循环对子序列的数组进行赋值,代码冗余度很大,不提倡。
出现的问题和结论
1、习惯用VS等电脑自身的IDE运行程序和OJ系统还是有一定的区别的,初步使用OJ系统难免会出现一些低级错误,要注意多多练习。
2、树型数据结构是平时考试、面试等的重点,要多加练习,多总结,多反思。