《剑指Offer》学习笔记--面试题6:重建二叉树

题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出此二叉树并输出它的头结点。二叉树节点的定义如下:

struct  BinaryTreeNode

{

      int                          m_nValue;

      BinaryTreeNode*  m_pLeft;

      BinaryTreeNode*  m_pRight;

};

解题思路:在二叉树的前序遍历序列中,第一个数字总是树的根结点的值。但在中序序列中,根结点的值在序列的中间,左子树的结点的值位于根节点的值的左边,而右子树的结点的值位于根结点的值的右边。因此我们需要扫描中序遍历序列,才能找到根结点的值。

在想清楚如何在前序遍历和中序遍历的序列中确定左、右子树的子序列之后,我们可以写出如下的递归代码:

#include <iostream>
using namespace std;
typedef struct BinaryTreeNode{
	int                  data;
	struct BinaryTreeNode* lchild;
	struct BinaryTreeNode* rchild;
};

BinaryTreeNode* ConstructCore
	(
	   int *startPreorder, int *endPreorder,
	   int *startInorder,  int *endInorder 
	);

BinaryTreeNode* Construct(int *preorder, int *inorder, int length)
{
	if(preorder == NULL || inorder == NULL || length <= 0){
		return NULL;
	}
	return ConstructCore(preorder, preorder+length-1, inorder, inorder+length-1);
}

BinaryTreeNode* ConstructCore
	(
	   int *startPreorder, int *endPreorder,
	   int *startInorder,  int *endInorder 
	)
{
	//前序遍历序列第一个数字是根结点的值
	BinaryTreeNode* root = new BinaryTreeNode();
	int rootValue = startPreorder[0];
	root->data = rootValue;
	root->lchild = root->rchild = NULL;

	if(startPreorder == endPreorder){
		if(startInorder == endInorder 
			&& *startPreorder == *startInorder)//只有一个节点了
			return root;
		else
			throw std::exception("Invalid input.");
	}

	//在中序遍历中找到根结点的值
	int *rootInorder = startInorder;
	while(rootInorder <= endInorder && *rootInorder != rootValue){
		++rootInorder;
	}

	if(rootInorder == endInorder && *rootInorder != rootValue){
		throw std::exception("Invalid input.");
	}

	int leftLength = rootInorder - startInorder;
	int *leftPreorderEnd = startPreorder + leftLength;
	if(leftLength > 0){
		//构建左子树
		root->lchild = ConstructCore(startPreorder+1, leftPreorderEnd, 
			        startInorder, rootInorder-1);
	}
	if(leftLength < endPreorder - startPreorder){
		//构建右子树
		root->rchild = ConstructCore(leftPreorderEnd+1, endPreorder, 
			        rootInorder+1, endInorder);
	}
	return root;
}
//打印出构建后二叉树的后序遍历序列
void PrintLorder(BinaryTreeNode *root) 
{
	if(root != NULL){
		PrintLorder(root->lchild);
		PrintLorder(root->rchild);
		cout<<root->data<<" ";
	}
}
int main()
{
	int preOrder[] = {1,2,4,7,3,5,6,8};
	int inOrder[] = {4,7,2,1,5,3,8,6};
	int length = sizeof(preOrder)/sizeof(int);
	BinaryTreeNode *root = Construct(preOrder, inOrder, length);
	PrintLorder(root);
	system("pause");
	return 0;
}
在函数ConstrucCore中,我们先根据前序遍历序列的第一个数字创建根结点,接下来在中序序列中找出根结点的位置,这样就能确定左、右子树结点的数量。在前序遍历和中序遍历的序列中划分了左、右子树结点的值之后,我们就可以递归地调用函数ConstructCore,分别构建它的左右子树。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧农业是一种结合了现代信息技术,包括物联网、大数据、云计算等,对农业生产过程进行智能化管理和监控的新模式。它通过各种传感器和设备采集农业生产中的关键数据,如大气、土壤和水质参数,以及生物生长状态等,实现远程诊断和精准调控。智慧农业的核心价值在于提高农业生产效率,保障食品安全,实现资源的可持续利用,并为农业产业的转型升级提供支持。 智慧农业的实现依赖于多个子系统,包括但不限于设施蔬菜精细化种植管理系统、农业技术资料库、数据采集系统、防伪防串货系统、食品安全与质量追溯系统、应急追溯系统、灾情疫情防控系统、农业工作管理系统、远程诊断系统、监控中心、环境监测系统、智能环境控制系统等。这些系统共同构成了一个综合的信息管理和服务平台,使得农业生产者能够基于数据做出更加科学的决策。 数据采集是智慧农业的基础。通过手工录入、传感器自动采集、移动端录入、条码/RFID扫描录入、拍照录入以及GPS和遥感技术等多种方式,智慧农业系统能够全面收集农业生产过程中的各种数据。这些数据不仅包括环境参数,还涵盖了生长状态、加工保存、检验检疫等环节,为农业生产提供了全面的数据支持。 智慧农业的应用前景广阔,它不仅能够提升农业生产的管理水平,还能够通过各种应用系统,如库房管理、无公害监控、物资管理、成本控制等,为农业生产者提供全面的服务。此外,智慧农业还能够支持政府监管,通过发病报告、投入品报告、死亡报告等,加强农业产品的安全管理和质量控制。 面对智慧农业的建设和发展,存在一些挑战,如投资成本高、生产过程标准化难度大、数据采集和监测的技术难题等。为了克服这些挑战,需要政府、企业和相关机构的共同努力,通过政策支持、技术创新和教育培训等手段,推动智慧农业的健康发展。智慧农业的建设需要明确建设目的,选择合适的系统模块,并制定合理的设备布署方案,以实现农业生产的智能化、精准化和高效化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值