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

news2024/9/23 21:27:33

一、题目描述与要求

序列化二叉树_牛客题霸_牛客网 (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.coloradmin.cn/o/1079742.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

apple pencil有没有必要买?口碑好的电容笔推荐

相信很多小伙伴都在纠结&#xff0c;该选哪一支电容笔呢&#xff1f;一款原装的Apple Pencil&#xff0c;售价接近1000元&#xff0c;这个价位&#xff0c;在许多人的眼中&#xff0c;已经是相当的高了。其实&#xff0c;平替电容笔的价格很低&#xff0c;一两百块钱就能买到&a…

C/C++: * 和 *的区别

/** * * Althor:Hacker Hao * Create:2023.10.11 * */#include <bits/stdc.h> using namespace std; void fun1(int* ptr) {*ptr 3;ptr NULL; //不会改变原指针所指向的对象 }void fun2(int*& ptr) {*ptr 2;ptr NULL; //会改变原指针所指向的对象//也就…

2023年9月国产数据库大事记-墨天轮

本文为墨天轮社区整理的2023年9月国产数据库大事件和重要产品发布消息。 目录 9月国产数据库大事记 TOP109月国产数据库大事记&#xff08;时间线&#xff09;产品/版本发布兼容认证代表厂商大事记排行榜新增数据库厂商活动相关资料 9月国产数据库大事记 TOP10 9月国产数据库…

第十一章 共用体union和枚举enum

共用体 概念 有时想用同一段内存单元存放不同类型的变量。例如&#xff0c;把一个短整型变量&#xff0c;一个字符型变量和一个实型变量放在同一个地址开始的内存单元中 1000地址。以上3个变量在内存中占的字节数不同&#xff0c;但都从同一地址开始(图中设地址为1000)存放&a…

推荐高效的电脑磁盘备份解决方案!

该怎样实现电脑磁盘备份&#xff1f; 接下来&#xff0c;我们将为你介绍两种磁盘备份方法。一种是利用操作系统自带的功能&#xff0c;另一种则是通过第三方工具实现。 方法一. Windows自带的备份还原功能 要在Windows 11/10/8/7中备份软件&#xff0c;你可以使…

Linux shell编程学习笔记10:expr命令 和 算术运算

Linux Shell 脚本编程和其他编程语言一样&#xff0c;支持算数、关系、布尔、字符串、文件测试等多种运算。上节我们研究了 Linux shell编程 中的 字符串运算&#xff0c;今天我们研究 Linux shell编程的算术运算 &#xff0c;为了方便举例&#xff0c;我们同时对expr命令进行…

物联网AI MicroPython传感器学习 之 Relay继电器模块

学物联网&#xff0c;来万物简单IoT物联网&#xff01;&#xff01; 一、产品简介 继电器&#xff08;英文名称&#xff1a;relay&#xff09;是一种电控制器件&#xff0c;是当输入量的变化达到规定要求时&#xff0c;在电气输出电路中使被控量发生预定的阶跃变化的一种电器。…

linux查看文件内容命令more/less/cat/head/tail/grep

1.浏览全部内容more/less 文件&#xff1a; more&#xff1a;可以查看文件第一屏的内容&#xff0c;同时左下角有一个显示内容占全部文件内容的百分比&#xff0c;空格键会显示下一屏的内容&#xff0c;直到文件末尾 [rootmaster data]# more file1less&#xff1a;相较于mor…

前端工程化(editorconfig+ESLint+Prettier+StyleLint+Husky、Commitlint)

前言 致谢&#xff1a;有来技术大大 通过学习有来技术大大的文章和结合自己的实践&#xff0c;写一篇笔记记录一下 所使用的工具&#xff1a; ide项目风格(editorconfig)代码检查(ESLint)代码风格(Prettier)样式风格(StyleLint)git提交规范(Husky、Commitlint) 一、ide项目…

【算法设计与分析】— —单源最短路径的贪心算法

&#x1f383;欢迎大家前去观看我的算法设计与分析专栏&#xff1a; 算法设计与分析_IT闫的博客-CSDN博客 希望对大家有所帮助&#xff01; &#x1f383;个人专栏&#xff1a; &#x1f42c; 算法设计与分析&#xff1a;算法设计与分析_IT闫的博客-CSDN博客 &#x1f433;Java…

玉柴集团用USB Server对U盾远程安全管控

在当今数字化时代&#xff0c;企业的业务规模和组织结构日益复杂&#xff0c;对于U盾这样小小的&#xff0c;但却异常重要的USB设备的管理和使用提出了更高的要求。广西玉柴机器股份有限公司作为一家综合性集团企业&#xff0c;其业务规模庞大&#xff0c;组织结构复杂&#xf…

MapReduce(林子雨慕课课程)

文章目录 7. MapReduce7.1 MapReduce简介7.1.1 分布式并行编程7.1.2 MapReduce模型简介 7.2 MapReduce体系结构7.3 MapReduce工作流程概述7.4 Shuffle过程原理7.5 MapReduce应用程序的执行过程7.6 WordCount实例分析7.7 MapReduce的具体应用7.8 MaReduce编程实践 7. MapReduce …

案例研究|DataEase助力无锡布勒业务数据可视化建设

布勒集团是一家来自瑞士的家族企业&#xff0c;在谷物与食品以及先进材料制造等领域深耕超过160年。布勒大中华区的总部位于江苏无锡。无锡布勒是一家集研发、生产、销售于一体的综合性公司&#xff0c;拥有先进的生产设备及高素质的科技研发人员&#xff0c;以谷物深加工、谷物…

代码随想录第41天 | 123.买卖股票的最佳时机III ● 188.买卖股票的最佳时机IV

123.买卖股票的最佳时机III /*** param {number[]} prices* return {number}*/ var maxProfit function (prices) {const len prices.lengthconst dp new Array(len).fill(0).map(x > new Array(5).fill(0));// 第一天买入&#xff08;第一次买入&#xff09;dp[0][1] …

c 语言基础题目:PTA L1-033 出生年

以上是新浪微博中一奇葩贴&#xff1a;“我出生于1988年&#xff0c;直到25岁才遇到4个数字都不相同的年份。”也就是说&#xff0c;直到2013年才达到“4个数字都不相同”的要求。本题请你根据要求&#xff0c;自动填充“我出生于y年&#xff0c;直到x岁才遇到n个数字都不相同的…

Jetson Orin NX 开发指南(2): 基本环境配置

本文主要是在 Jetson Orin NX 系统烧录和组件安装完成后&#xff0c;对系统进行一些基本的配置&#xff0c;需要注意的是这里的系统其实也是 ubuntu 系统&#xff0c;并且由于选择的是 &#xff0c;其对应的是 ubuntu 20.04 系统&#xff0c;接下来我将介绍一些基本的配置。 一…

【动态规划】是泰波那契数,不是斐波那契数

Problem: 1137. 第 N 个泰波那契数 文章目录 题目解读解题方法dp动态规划迭代优化✔ 复杂度Code 题目解读 首先我们来解读一下本题的意思&#x1f50d; 相信读者在看到【泰波那契数】的时候&#xff0c;不禁会联想到【斐波那契数】&#xff0c;它们呢是一对孪生兄弟&#xff0c…

【d2l动手学深度学习】 Lesson 10 多层感知机 + 代码实现 试验结果对比

文章目录 1. 介绍2. 单层Softmax回归2.1 手写Softmax训练效果 2.2 调用pytorch内置的softmax回归层实现调用pytorch内置softmax实验结果总结 3. 一层感知机&#xff08;MLP&#xff09; Softmax实验结果 Reference写在最后 1. 介绍 在第十节课 多层感知机 的代码实现部分&…

前后端分离项目-基于springboot+vue的足球青训俱乐部管理后台系统的设计与实现(内含代码+文档+报告)

博主介绍&#xff1a;✌全网粉丝10W,前互联网大厂软件研发、集结硕博英豪成立工作室。专注于计算机相关专业毕业设计项目实战6年之久&#xff0c;选择我们就是选择放心、选择安心毕业✌ &#x1f345;由于篇幅限制&#xff0c;想要获取完整文章或者源码&#xff0c;或者代做&am…

4个不限字数的AI智能写作网站,用好任意一个就可以了

我们都在互联网上写过内容&#xff0c;有的人写社交媒体帖子、电子邮件或文本&#xff0c;有的人为我们的网站、产品描述、视频内容、广告甚至客户支持撰写内容。最近&#xff0c;*******推出了友好的类似聊天机器人的界面&#xff0c;使得AI写作更加容易访问&#xff0c;并迅速…