剑指offer——JZ37 序列化二叉树 解题思路与具体代码【C++】

一、题目描述与要求

序列化二叉树_牛客题霸_牛客网 (nowcoder.com)

题目描述

请实现两个函数,分别用来序列化和反序列化二叉树,不对序列化之后的字符串进行约束,但要求能够根据序列化之后的字符串重新构造出一棵与原二叉树相同的树。

二叉树的序列化(Serialize)是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树等遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#)
二叉树的反序列化(Deserialize)是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。

例如,可以根据层序遍历的方案序列化,如下图:

层序序列化(即用函数Serialize转化)如上的二叉树转为"{1,2,3,#,#,6,7}",再能够调用反序列化(Deserialize)将"{1,2,3,#,#,6,7}"构造成如上的二叉树。

当然你也可以根据满二叉树结点位置的标号规律来序列化,还可以根据先序遍历和中序遍历的结果来序列化。不对序列化之后的字符串进行约束,所以欢迎各种奇思妙想。

数据范围:节点数 n≤100,树上每个节点的值满足 0≤val≤150

要求:序列化和反序列化都是空间复杂度O(n),时间复杂度 O(n)

示例

示例1:

输入:{1,2,3,#,#,6,7}

返回值:{1,2,3,#,#,6,7}

说明:如题面图

示例2:

输入:{8,6,10,5,7,9,11}

返回值:{8,6,10,5,7,9,11}


二、解题思路

根据题目要求,我们要对给定二叉树先进行序列化(先序/中序/后序/层次)【这里选择的是先序遍历】,从而获得对应的先序遍历序列,其中空子树用‘#’代替。然后再根据这个序列去还原出原来的二叉树,也就是反序列。

首先我们先将二叉树进行序列化,也就是实现先序遍历。

存储遍历序列结果可以选择字符数组或者字符串,因为树的大小不可知,如果采用字符数组的话需要提前定义较大容量,可能会出现浪费空间的情况,因此我们可以选择先利用string存储,然后在根据字符串的长度来为字符数组申请空间(因为函数要求返回数据为char*),然后将string的内容复制过去即可。记得添加上结束符!

先判断当前是否为空树,如果是的话直接返回“#”即可;

然后调用先序遍历函数对二叉树进行先序遍历并获取序列;

接着把获取的序列存到字符数组中,添加结束符,返回即可。

先序遍历二叉树并获取序列函数实现:【递归】

首先判断当前结点是否为空,如果是的话则将‘#’添加到str中,同时返回父节点;(递归结束标志)

然后获取结点中的数据,因为结点值为int,所以需要进行类型转换成string存入temp,然后将temp添加到str后面,同时由于结点值是数字,可能会有多位数,因而我们在添加完每一个结点值后添加分隔符‘;’,用于区分结点;

然后分别递归遍历左子树和右子树,直至整颗二叉树遍历结束,即可获得先序遍历序列str。

【需要注意的是,这里的函数参数str是引用方式传递,因为在递归过程中我们需要修改str的值,如果不用&,在递归函数内部修改str的值并不会影响到函数外部的指针,因此无法正确更新str】

解决完序列化二叉树之后,我们就需要利用所得的序列来还原二叉树。

首先判断序列是否等于“#”,如果是的话代表这一二叉树为空树,则直接返回空;

否则的话定义结点res用来接收还原后的二叉树的根结点用于返回。

【由于在递归中可能多次修改str的值,所以为了保持指针的引用,在每次递归调用时传递&str;通过传递&str,可以在递归函数中更新str的值,这样在返回上层递归时,指针的位置会继续向后移动,指向下一个要解析的字符。而如果只是传递str,在递归函数内部修改str的值并不会影响到函数外部的指针,因此无法正确更新遍历的位置。因此函数参数为char *&str

想要获取每个结点值,那么肯定需要对所给的字符数组进行遍历,但是由于从string赋值给数组的结果可以知道,数组中每个元素存储的并不是单个结点的值,这也就是在序列化时需要添加分隔符的原因,因此比起利用for循环遍历数组,我们可以利用指针遍历数组会更方便。

首先判断当前字符是否为'#',是的话代表当前结点为空节点,因而让指针后移到下一个字符,然后返回空;

否则的话,我们需要取获取当前结点的值,因为结点值可能是多位数,所以我们利用while循环找到分隔符,并且利用变量val来获取结点值,比如结点值为12,那么在数组中就是12;因而根据这一规律计算原结点值,同时指针后移;

然后利用结点的构造函数构建结点,如果此时一定访问到字符数组末尾,则返回当前结点;

否则的话指针后移(因为当前为分割符);

然后分别构造对应的左子树与右子树,最后返回根结点。


三、具体代码

/*
struct TreeNode {int val;struct TreeNode *left;struct TreeNode *right;TreeNode(int x) :val(x), left(NULL), right(NULL) {}
};
*/
#include <string>
class Solution {
public://对二叉树进行先序遍历 并存储所得序列void PreOrderTraver(TreeNode* root,string& str){//如果当前结点为空,则用#表示 并返回父节点if(root==nullptr){str+='#';return;}string temp=to_string(root->val);//将结点中的值存入字符串中,因为结点值是数字,会有多位数 因而加一个标识符用来区别结点str+=temp+';';//对左右子树进行遍历PreOrderTraver(root->left, str);PreOrderTraver(root->right, str);}char* Serialize(TreeNode *root) {    //如果是空树则直接返回#if(root==nullptr) return "#";string res;//存储先序遍历后的序列PreOrderTraver(root, res);//把获取的结果string转成char*类型 因为题目要求返回char*char* charRes=new char[res.length()+1];strcpy(charRes,res.c_str());//将内容复制过去charRes[res.length()]='\0';//添加结束符return charRes;}TreeNode* Restore(char *&str){//因为字符数组中存储的内容并不是单个结点的值//因此我们需要利用指针去对字符数组进行访问if(*str=='#'){str++;return nullptr;}int val=0;while(*str!=';'&&*str!='\0'){val=val*10+((*str)-'0');str++;}TreeNode* root=new TreeNode(val);if(*str=='\0') return root;else str++;root->left=Restore(str);root->right=Restore(str);return root;}//反序列——根据先序遍历所得的序列还原二叉树TreeNode* Deserialize(char *str) {//空树则返回空if(str=="#") return nullptr;//获取还原结果//由于在递归中可能多次修改str的值,所以为了保持指针的引用,在每次递归调用时传递&str//通过传递&str,可以在递归函数中更新str的值,这样在返回上层递归时,指针的位置会继续向后移动,指向下一个要解析的字符。//而如果只是传递str,在递归函数内部修改str的值并不会影响到函数外部的指针,因此无法正确更新遍历的位置。TreeNode* res=Restore(str);return res;}
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/131037.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【算法|动态规划No.16】leetcode931. 下降路径最小和

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

2023年中国医院信息系统发展现状及行业市场规模分析[图]

医院信息系统&#xff0c;亦称“医院管理信息系统”&#xff08;简称HIS&#xff09;&#xff0c;是指利用计算机软硬件技术、网络通信技术等现代化手段&#xff0c;对医院及其所属各部门的人流、物流、财流进行综合管理&#xff0c;对在医疗活动各阶段产生的数据进行采集储存、…

vscode 调试使用 make 编译的项目

1、首先点击运行 --> 启动调试&#xff1a; 2、选择g或gcc生成和调试活动文件&#xff1a; 3、出现下面提示是正常的&#xff0c;点击仍要调试&#xff1a; 点击打开“launch.json”&#xff1a; 4、此时会在项目工作目录下生成tsak.josn和launch.json文件&#xff1a; 如…

力扣(LeetCode)2512. 奖励最顶尖的K名学生(C++)

优先队列哈希集合反向思维(或自定义排序) 模拟&#xff0c;请直接看算法思路&#xff1a; 两个哈希集合S1和S2, S1存正面词汇&#xff0c;S2存负面词汇&#xff1b;一个优先队列pq&#xff0c;pq存{score, id}键值对&#xff0c;即学生分数-学生id。 算法流程&#xff1a; 初…

Android 面经总结分享(相当走心)

背景描述 这是来自一位粉丝朋友的面经分享&#xff0c;他在 「Android 开发行业」 摸爬滚打5年多的开发&#xff0c;呆过的互联网公司有三家&#xff0c;均从事的Android 开发的工作。最后离职的一家公司也是做的最久的一家&#xff0c;工作了将近3年多时光。 废话不多说了&a…

山西电力市场日前价格预测【2023-10-12】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2023-10-12&#xff09;山西电力市场全天平均日前电价为506.23元/MWh。其中&#xff0c;最高日前电价为841.91元/MWh&#xff0c;预计出现在18: 30。最低日前电价为351.76元/MWh&#xff0c;预计…

1600*A. Maze(DFS)

Problem - 377A - Codeforces 解析&#xff1a; 对于正向思考比较复杂的题目&#xff0c;我们可以反向思考。 由于最后剩余的 “ . ” 必须相连&#xff0c;所以我们将所有 “ . ” 全部换成 “ X ”&#xff0c;然后从其中DFS一个联通的“ X ”反向换成 “ . ”即可。 #incl…

2023年中国医学影像信息系统市场规模、竞争格局及行业趋势分析[图]

医学影像信息系统简称PACS&#xff0c;与临床信息系统、放射学信息系统、医院信息系统、实验室信息系统同属医院信息系统。医学影像信息系统是处理各种医学影像信息的采集、存储、报告、输出、管理、查询的计算机应用程序。主要包括&#xff1a;预约管理、数据接收、影像处理、…

RxJava介绍及基本原理

随着互联网的迅猛发展&#xff0c;Java已成为最广泛应用于后端开发的语言之一。而在处理异步操作和事件驱动编程方面&#xff0c;传统的Java多线程并不总是最佳选择。这时候&#xff0c;RxJava作为一个基于观察者模式、函数式编程和响应式编程理念的库&#xff0c;为我们提供了…

TensorFlow入门(十七、神经元的拟合原理)

深度学习的概念源于人工神经网络的研究,神经网络是由多个神经元组成,。一个神经元由以下几个关键知识点组成: ①激活函数 ②损失函数 ③梯度下降 单个神经元的网络模型如图所示 用计算公式表达如下: z为输出的结果,x为输入,w为权重,b为偏置值。z…

数据结构--》解锁数据结构中树与二叉树的奥秘(二)

数据结构中的树与二叉树&#xff0c;是在建立非线性数据结构方面极为重要的两个概念。它们不仅能够模拟出生活中各种实际问题的复杂关系&#xff0c;还常被用于实现搜索、排序、查找等算法&#xff0c;甚至成为一些大型软件和系统中的基础设施。 无论你是初学者还是进阶者&…

【排序算法】选择排序

文章目录 一&#xff1a;基本介绍1.1 概念1.2 算法思想1.3 思路分析图1.4 思路分析1.5 总结1.5.1 选择排序一共有数组大小-1轮排序1.5.2 每一轮排序&#xff0c;又是一个循环&#xff0c;循环的规则如下&#xff08;在代码中实现&#xff09;&#xff1a; 二&#xff1a;代码实…