剑指offer_04_重建二叉树

剑指offer第四题:重建二叉树

题目描述

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

二叉树节点数据结构如下:

struct TreeNode {

int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}

};

重建二叉树函数声明如下

TreeNode* reConstructBinaryTree(vector<int> pre, vector<int> vin) ;

数据结构与算法基础也不扎实,看到这道题是一脸懵逼的。这道题主要涉及到二叉树和递归(递归应该是此题最经典的解法)。本文也就主要分这两个方面记录一下。重点是自己对递归的初步理解。

二叉树

二叉树直接参考剑指offer书中所讲。要掌握二叉树的前序、中序、后序遍历,这里的前中后也就是根节点与左右子节点的相对位置,前序 根-左-右,中序  左-根-右,后续 左-右-根。二叉树每个节点的典型构成为  节点数据+左右两个指针。

递归

按照我自己的理解,递归分为两个部分。

    1)递归调用(调用自己)

    2)递归出口(到某种状态不用再调用自己)

先解决一个简单的递归问题--求n的阶乘

我觉得递归最难的地方是写出递归关系,所以遇到递归问题,先写出几个简单的case看一下,找一下规律,先将递归关系搞明白,什么时候需要调用自己。令求阶乘函数为f(n)。

case  1 :n=1时,f(1)=1;

case 2 :n=2时,f(2)=2*1;

case 3:n=3时,f(3)=3*2*1;

我们将case3中2*1看做一个整体,已经可以发现f(3)=3*f(2)了,容易想到f(n)=n*f(n-1),暂时不管递归出口,先根据递归关系写出一个初步的f(n)函数出来。

long f(int n)

{

return n*(f(n-1));

}

函数主体完成,接下来尝试找递归出口,

n最小能取0,当n=0时,我们不可能再让函数去调用自己吧,当递归进行不下去,无法再调用自己的时候,就是递归的边界,而f(0)=1。其实f(2)=2也可以作为递归出口,当然这需要看n的取值范围,比如如果n>=10,完全可以将f(2)、f(3)、f(10)作为递归出口。

long f(int n)

{

return (n==0?1:n*f(n-1));

}

再看递归的经典问题--汉诺塔


还是按照上次的思路,画几个简单的case找到递推关系,case1当有1个圆盘时直接从柱1->柱3即可,记为1->3;case2当有两个圆盘时,有3步1->2,1->3,2->3。那么3个呢?此时已经感觉不太好解了,尝试寻找递归关系。对于2个圆盘,通过case2的方法可以将两个圆盘在3根柱子上随意移动,那既然可以将2个圆盘随意移动,干脆就直接把两个当成一个好了。于是将case3上的两个圆盘当做一个盘。令函数为move(n,src,temp,dst),case3可写成move(3,z1,z2,z3),由于将case3上的两个圆盘当做一个盘,那么case3就变为了case2,用3步即可完成,1(2个)->2,1(1个)->3,2(2个)->3,写成函数:move(2,z1,z3,z2)->move(1,z1,z2,z3)->move(2,z2,z1,z3)。至此,已经找到递归关系,将move(3,z1,z2,z3)分解为了move(2,z1,z3,z2)->move(1,z1,z2,z3)->move(2,z2,z1,z3),推广:move(n,z1,z2,z3)分解为move(n-1,z1,z3,z2)->move(1,z1,z2,z3)->move(n-1,z2,z1,z3),代码如下:

void move(int n, char z1, char z2, char z3){
move(n - 1, z1, z3, z2);
move(1, z1 ,z2, z3);
move(n - 1, z2, z1, z3);
}

接下来再寻找递归出口,n最小为1,n=1时,move无法再调用自己,所以n=1时,直接打印结果。加入递归出口后程序如下。

void move(int n, char z1, char z2, char z3){

if (n == 1) {
cout <<   z1 << "->" << z3 << ',';
}
else {
move(n - 1, z1, z3, z2);
move(1, z1 ,z2, z3);
move(n - 1, z2, z1, z3);
}

}

接下来回到本题使用递归重建二叉树

继续延续之前的思路,先从小case得到递归流程。                                                                                                                

将上图三种case依次记为case1、case2、case3。先将函数声明TreeNode* reConstructBinaryTree(vector<int> pre, vector<int> vin) 

case1时:

TreeNode* reConstructBinaryTree({1}, {1} 

{

   return new TreeNode(1);

}

case2时:

TreeNode* reConstructBinaryTree({1,2,3},{2,1,3}) 

{

   TreeNode* root=new TreeNode(1);

   root->left=new TreeNode(2);

   root->right=new TreeNode(3);

   return root;

}

case3时,从上图注意到,如果将1的左子树看成一个整体,那么case3就变成了case2,在case3中为left指针赋值时,令left等于2和4构成的左子树的root指针即可。

TreeNode* reConstructBinaryTree({1,2,4,3},{4,2,1,3}

{

   TreeNode* root=new TreeNode(1);

   root->left=reConstructBinaryTree({2,4}, {4,2});

   root->right=new TreeNode(pre[3]);

   return root;

}

至此,便已得到递归关系,根据前序遍历得到根节点的值,然后将前序、中序遍历划分,分别得到根节点左右子树的前序、中序遍历。令当前节点的left等于重建的左子树的树根,right等于重建的右子树的树根。

TreeNode* reConstructBinaryTree(vector<int> pre, vector<int> vin) 

{

   TreeNode* root=new TreeNode(pre[0]);

{     将前序、中序遍历划分,分别得到根节点左右子树的前序、中序遍历

vector<int> new_pre_l, new_vin_l, new_pre_r, new_vin_r;     }   

if(new_pre_l.size()>0)root->left = reConstructBinaryTree(new_pre_l, new_vin_l);

if(new_pre_r.size()>0)root->right = reConstructBinaryTree(new_pre_r, new_vin_r);

return root;

}

还需要为程序添加递归出口,先进行空树判断,若前序、中序遍历为空,直接返回空指针即可,而当前序、中序遍历只有一个值的时候便可直接返回当前节点,因为该节点不存在左右儿子。

TreeNode* reConstructBinaryTree(vector<int> pre, vector<int> vin) 

{

if(pre.size()==0)return NULL;

 TreeNode* root=new TreeNode(pre[0]);

  if(pre.size()==1)return root;

{     将前序、中序遍历划分,分别得到根节点左右子树的前序、中序遍历

vector<int> new_pre_l, new_vin_l, new_pre_r, new_vin_r;     }   

if(new_pre_l.size()>0)root->left = reConstructBinaryTree(new_pre_l, new_vin_l);

if(new_pre_r.size()>0)root->right = reConstructBinaryTree(new_pre_r, new_vin_r);

return root;

}

重建二叉树完整代码如下:

TreeNode* reConstructBinaryTree(vector<int> pre, vector<int> vin) {
int length = pre.size();
if (length == 0)return NULL;
int root_val = pre[0];
TreeNode* root = new TreeNode(root_val);
if (length == 1)return root;

vector<int> new_pre_l, new_vin_l, new_pre_r, new_vin_r;
for (int i = 0; i < length; i++){
if (vin[i] == root_val)break;
else new_vin_l.push_back(vin[i]);
}
int left_size = new_vin_l.size();
for (int i = 1; i <= left_size; i++)
new_pre_l.push_back(pre[i]);
for (int i = left_size + 1; i < length; i++){
new_pre_r.push_back(pre[i]);
new_vin_r.push_back(vin[i]);
}
int right_size = new_pre_r.size();

if (left_size > 0)root->left = reConstructBinaryTree(new_pre_l, new_vin_l);
if (right_size > 0)root->right = reConstructBinaryTree(new_pre_r, new_vin_r);
return root;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip
毕设新项目基于python3.7+django+sqlite开发的学生就业管理系统源码+使用说明(含vue前端源码).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 学生就业管理系统(前端) ## 项目开发环境 - IDE: vscode - node版本: v12.14.1 - npm版本: 6.13.4 - vue版本: @vue/cli 4.1.2 - 操作系统: UOS 20 ## 1.进入项目目录安装依赖 ``` npm install ``` ## 2.命令行执行进入UI界面进行项目管理 ``` vue ui ``` ## 3.编译发布包(请注意编译后存储路径) #### PS:需要将编译后的包复制到后端项目的根目录下并命名为'static' 学生就业管理系统(后端) ## 1.项目开发环境 - IDE: vscode - Django版本: 3.0.3 - Python版本: python3.7.3 - 数据库 : sqlite3(测试专用) - 操作系统 : UOS 20 ## 2.csdn下载本项目并生成/安装依赖 ``` pip freeze > requirements.txt pip install -r requirements.txt ``` ## 3.项目MySQL数据库链接错误 [点击查看解决方法](https://www.cnblogs.com/izbw/p/11279237.html)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值