Second Exercise:重建二叉树

题目要求:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回【来源于剑指offer】。

基本思路
1.先求出根节点(前序序列第一个元素)。
2.将根节点带入到中序遍历序列中求出左右子树的中序遍历序列。
3.通过左右子树的中序序列长度、位置关系带入前序遍历序列,求出左右子树的前序序列。
4.左右子树的前序序列第一个元素分别是根节点的左右儿子
5.求出了左右子树的4种序列可以递归上述步骤。

代码实现
方法一新建四个序列,分别存储前序中序的左右子树。
注释内容:理解代码之后独立完成过程中,曾犯过的错误以及相应的思考,并非对程序思路的解读。

#include<iostream>
#include<vector>
struct TreeNode //此处无指针
{
	int val;
	TreeNode* Left; //指针符号紧跟哪个,有讲究吗???
	TreeNode* Right;
	//注意结构体以及初始化格式:逗号,{},无分号
	TreeNode(int x) :val(x), Left(NULL), Right(NULL) {}
};  
TreeNode* reConstructBinaryTree(std::vector<int> pre, std::vector<int> vin) 
{
	if (pre.size() == 0 || vin.size() == 0)
		return NULL;
		
	std::vector<int> pre_left, pre_right,vin_left,vin_right;
	
	// 定义类型一定为指针型,到现在还不是特别理解,需要补一些基础知识啦~~
	//初始化时要用new啊,不是直接TreeNode *tree(pre[0])!!!
	//再次在new处踩坑,明明错误提示没有初始化就是不知道怎么改!!!	
	TreeNode* root=new TreeNode(pre[0]);
	
	int i = 0;
	for (i = 0; vin[i] != pre[0]; i++);
	
	for (int j = 0; j < pre.size(); j++)
	{
		if (j < i)
		{
			//向量要压入压出,不是直接赋值
			//pre_left[order] = pre[order+1];
			pre_left.push_back(pre[j+1]);//注意要加一
			vin_left.push_back(vin[j]);
		}
		if (j > i)
		{
			//注意序号,无需与i做加减运算
			pre_right.push_back(pre[j]);
			vin_right.push_back(vin[j]);
		}

	}
	root->Left = reConstructBinaryTree(pre_left, vin_left);
	root->Right = reConstructBinaryTree(pre_right, vin_right);
	return root;
}
void main()
{
	TreeNode* tree;
	std::vector<int> pre = { 1,2,4,7,3,5,6,8 };
	std::vector<int> vin = { 4,7,2,1,5,3,8,6 };
	tree = reConstructBinaryTree(pre, vin);
	return 1;
}

代码实现
方法二没有新建序列,而是在原序列中不断更新左右子树的边界值完成递归,因此,向量形参为pre vin永远未改变。
注释内容:理解代码之后独立完成过程中,曾犯过的错误以及相应的思考理解。

#include<iostream>
#include<vector>
struct TreeNode
{
	int val;
	TreeNode* Left;
	TreeNode* Right;
	TreeNode(int x):val(x),Left(NULL),Right(NULL){}
};
TreeNode* reConstructBinaryTree(std::vector<int> pre, int pre_left, int pre_right, std::vector<int> vin, int vin_left, int vin_right)
{
	//由于pre vin序列未改变,只能通过边界判断子树是否为空;不能通过pre.size()判断,曾在此处踩坑,误以为等价
	if (pre_left > pre_right || vin_left > vin_right)
		return NULL;
	TreeNode* tree = new TreeNode(pre[pre_left]);
	//for (i = 0; pre[0] != in[i]; i++);
	/*前序遍历边界确定前序遍历的新子树;中序遍历边界确定中序遍历的新子树,所以,i应该从in_first开始而不是pre_first;不可混淆,曾在此处踩坑,且每层递归的内容为左右边界确定的新子树,所以,函数中应全部为形参pre_first,不应出现 0 作为数组首位*/
	//for (int i = 0; i < pre.size(); i++)//此处虽然正确,但增大了循环量//(20181221更新)此处不正确,若不限定范围,对于对称树,有重复值,会出现问题
	for (i = in_first; i < in_last + 1; i++)
	{
		if (pre[pre_left] == vin[i])
		{
			/*计算递归边界实参:容易确定vin序列左右子树边界,通过pre、vin序列长度相等来确定pre序列左右子树的边界;不要轻易地
			以为in的左子树的右边界为i;仅仅第一次时符合,递归至第二层时已经不符合了*/
			tree->Left = reConstructBinaryTree(pre, pre_left + 1, i - vin_left + pre_left, vin, vin_left, i - 1);
			//前序序列的左子树右边界+1即为右子树的左边界,或者根据长度相等来确定
			tree->Right = reConstructBinaryTree(pre, i - vin_left + pre_left + 1, pre_right, vin, i + 1, vin_right);
		}
	}
	return tree;
}

TreeNode* reConstructBinaryTree(std::vector<int> pre, std::vector<int> vin)
{
	TreeNode* tree = reConstructBinaryTree(pre, 0, pre.size() - 1, vin, 0, pre.size() - 1);
	return tree;
}

void main()
{
	TreeNode* tree;
	std::vector<int> pre = { 1,2,4,7,3,5,6,8 };
	std::vector<int> vin = { 4,7,2,1,5,3,8,6 };
	tree = reConstructBinaryTree(pre, vin);
	return 1;
}

曾因未初始化提示错误查错时,看到如下内容,目前不太理解,不太会用Call Stack去调试程序。

按Alt+7键查看Call Stack即“调用堆栈”里面从上到下列出的对应从里层到外层的函数调用历史。双击某一行可将光标定位到此次调用的源代码或汇编指令处,看不懂时双击下一行,直到能看懂为止。

由于还没学习到时间复杂度、空间复杂度等相关内容,暂时对以上两种不同传参的方法还无法进行进一步分析。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值