数据结构与算法-二叉树-序列化与反序列化

news2024/11/20 12:45:38

可能性探究:我们可以想到的是只有一棵树按照某个序是唯一确定要给结构的情况才可能被序列化和反序列化,比如我们对于以下的二叉树可以找到它的先序、中序、后序如下:

 根据它的先序和后序我们找不到任何其他可能的树,所以可以根据先序和后序去做序列化和反序列化,但是中序就不是那么可靠,我们可以发现中序不止这一种可能性,反例如下:

看这个树是不是和上面那个树的中序一致,但是他们并不是同一棵树,所以中序不能用来做序列化和反序列化 

根据我们序列化和反序列化的相关知识,序列化和反序列化肯定都是一样的顺序

先序方式序列化,我们把结果放在数组里(也可以放在队列里)

        [“1”, “2”,null, "3", null, null, "4", null,null]

下标  0     1      2     3     4      5     6     7     8

反序列化时根据这个数组的内容,遇到null代表左子树或者又子树已经结束

根据这个进行反序列化创建树我们可以得到:

(1)先消费0位置(1),这是整棵树的头节点

(2)再消费1位置(2),这个位置时左子树的头节点

(3)消费2位置,发现位置为空,说明2的左子树为空,2这棵树的左子树终结

(4)消费3位置(3),开始建2的右树,把它作为2的右树的头节点

(5)消费位置4,开始建3的左子树,发现位置为空,说明3的左子树为空

(6)消费位置5,开始建3的右子树,发现位置为空,说明3的右子树为空

(7)消费位置6,此时1的整棵左数已经建完,开始建1的右树,位置6处的值为4,作为1的右树的头节点

(8)消费位置7, 开始建立4的左子树,发现这个位置为空,所以4的左子树为空。

(9)消费位置8, 开始建立4的右子树,发现这个位置为空,所以4的右子树为空。

整个数组消费完毕,反序列化结束,我们反序列化简历的树如下

 代码使用Queue代替数组实现

后序遍历序列化和反序列化跟先序的类似就不写了

下面分析层序遍历的序列化和反序列化,还是分析这棵树

 ans中的值最终依次为"1"  "2" "4"  null "3" null null null null

反序列化的过程和序列化类似:

(1)先取出序列化结果的第一个元素,然后建立Node作为头节点,入队(新建立的用于遍历的队列)

(2)如果队列不为空,弹出一个节点,并弹出序列化结果中的下面两项作为它的左子节点和右子节点,如果左右子节点有不为空的加入队列(先左后右)

(3)重复2的步骤,直到队列为空

先序、层序序列化和反序列化代码如下:

package dataStructure.binaryTree;

import dataStructure.TreeNode;

import java.util.LinkedList;
import java.util.Queue;

public class SerializeAndDeSerialize {
    public static void main(String[] args) {
        TreeNode t1 = new TreeNode(1);
        TreeNode t2 = new TreeNode(2);
        TreeNode t3 = new TreeNode(3);
        TreeNode t4 = new TreeNode(4);
        t1.left = t2;
        t1.right = t4;
        t2.right = t3;

        Queue<String> queue = preSerialize(t1);
        //printQueue(queue);
        TreeNode head = preDeSerialize(queue);
       // System.out.println(head);

        Queue<String> levelQueue = levelSerialize(t1);
        //printQueue(levelQueue);

        TreeNode head2 = levelDeSerialize(levelQueue);
        System.out.println(head2);
    }

    private static void printQueue(Queue<String> queue) {
        if(queue == null || queue.size() == 0) {
            return;
        }
       /* while(!queue.isEmpty()) {
            System.out.println(queue.poll());
        }*/
        queue.stream().forEach((x)-> System.out.println(x));
    }

    public static Queue<String> preSerialize(TreeNode head) {
        Queue<String> queue = new LinkedList<>();
        pres(head, queue);
        return  queue;
    }


    private static void pres(TreeNode head, Queue<String> queue) {
        if(head == null) {
            queue.add(null);
        } else {
            queue.add(String.valueOf(head.value));
            pres(head.left, queue);
            pres(head.right, queue);
        }
    }

    public static TreeNode preDeSerialize(Queue<String> queue) {
        if(queue == null) {
            return null;
        }
        //消费一个位置
        String value = queue.poll();
        if(value == null) {
            return null;
        }
        TreeNode head = new TreeNode(Integer.parseInt(value));
        //对于每个被消费位置的元素再消费两个位置
        //左子树的根节点消费一个
        head.left = preDeSerialize(queue);
        //右子树的根节点消费一个
        head.right = preDeSerialize(queue);
        //返回新建的树的根
        return head;
    }


    public static Queue<String> levelSerialize(TreeNode head) {
        if(head == null) return null;
        Queue<String> ans = new LinkedList<>();
        Queue<TreeNode> queue = new LinkedList<>();
        ans.add(String.valueOf(head.value));
        queue.add(head);
        while(!queue.isEmpty()) {
            TreeNode node = queue.poll();
            //只有不为空才加入queue
            if(node.left != null) {
                queue.add(node.left);
            }
            //不管是不是null都要加入ans中,注意判空
            ans.add(node.left == null ? null : String.valueOf(node.left.value));
            //只有不为空才加入queue
            if(node.right != null) {
                queue.add(node.right);
            }
            ans.add(node.right == null ? null : String.valueOf(node.right.value));
        }
        return ans;
    }

    public static TreeNode levelDeSerialize(Queue<String> queue) {
         if(queue == null || queue.size() == 0) {
             return null;
         }

         Queue<TreeNode> nodeQueue = new LinkedList<>();
         TreeNode head = new TreeNode(Integer.parseInt(queue.poll()));
         nodeQueue.add(head);
         while(!nodeQueue.isEmpty()) {
             TreeNode node = nodeQueue.poll();
             String next = queue.poll();
             node.left = next == null ? null : new TreeNode(Integer.parseInt(next));
             next = queue.poll();
             node.right = next == null ? null : new TreeNode(Integer.parseInt(next));
             if(node.left != null) {
                 nodeQueue.add(node.left);
             }
             if(node.right != null) {
                 nodeQueue.add(node.right);
             }
         }
         return head;
    }
}

欢迎批评指正

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

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

相关文章

NLP预训练模型

Models Corpus RoBERTa: A Robustly Optimized BERT Pretraining Approach 与BERT主要区别在于&#xff1a; large mini-batches 保持总训练tokens数一致&#xff0c;使用更大的学习率、更大的batch size&#xff0c;adam β20.98\beta_20.98β2​0.98&#xff1b;dynamic ma…

aws eks 集群初始化过程中pause容器的启动逻辑

eks集群默认策略在磁盘使用量达到threshold时会清除镜像&#xff0c;其中pause镜像也可能会被清除 https://aws.amazon.com/cn/premiumsupport/knowledge-center/eks-worker-nodes-image-cache/ pause容器能够为pod创建初始的名称空间&#xff0c;pod的内的容器共享其中的网络空…

库函数qsort 的模拟实现

在之前了解了库函数qsort的使用之后 我们来模拟实现一下上篇有介绍 qsort的底层实现是快速排序 由于害怕没有人了解过快速排序 我就用大家熟知的冒泡排序进行模拟实现 先来展示完整代码 以下代码为升序排序 如果降序将冒泡排序中的大于号改为小于号就可以了#define _CRT_SECURE…

malloc实现原理探究

2021年末面试蔚来汽车&#xff0c;面试官考察了malloc/free的实现机制。当时看过相关的文章&#xff0c;有一点印象&#xff0c;稍微说了一点东西&#xff0c;不过自己感到不满意。今天尝试研究malloc的实现细节&#xff0c;看了几篇博文&#xff0c;发现众说纷纭&#xff0c;且…

MySql启动错误(Mac系统 安装 mysql-8.0.32-macos13-arm64 后每次点击启动 无法启动) --- 已解决

MySql启动的时候: 立即变红! 查看日志如下: 2023-03-04T14:18:01.089671Z 0 [System] [MY-010910] [Server] /usr/local/mysql/bin/mysqld: Shutdown complete (mysqld 8.0.32) MySQL Community Server - GPL. 2023-03-04T14:18:10.304169Z 0 [System] [MY-010116] [Server]…

【EDA工具使用】——VCS和Verdi的联合仿真的简单使用

目录 1.芯片开发所需的工具环境 2.编译仿真工具 3.三步式混合编译仿真&#xff08;最常用&#xff09;​编辑 4.两步式混合编译仿真​编辑 5.VCS的使用 ​6.verdi的使用 1.产生fsdb文件的两种方法​编辑 1.芯片开发所需的工具环境 2.编译仿真工具 3.三步式混合编译仿真…

按位与为零的三元组[掩码+异或的作用]

掩码异或的作用前言一、按位与为零的三元组二、统计分组1、map统计分组2、异或掩码总结参考资料前言 当a b 0时&#xff0c;我们能够很清楚的知道b是个什么值&#xff0c;b 0 - a -a&#xff0c;如果当a & b 0时&#xff0c;我们能够很清楚的知道b是什么值吗&#xf…

Python GUI界面编程-初识

图形用户界面(Graphical User Interface&#xff0c;简称 GUI&#xff0c;又称图形用户接口)是指采用图形方式显示的计算机操作用户界面。与早期计算机使用的命令行界面相比&#xff0c;图形界面对于用户来说在视觉上更易于接受。然而这界面若要通过在显示屏的特定位置&#xf…

HiveSQL一天一个小技巧:如何精准计算非连续日期累计值【闪电快车面试题】

0 需 求稀疏字段累计求和问题1 问题分析根据图片中数据变换的形式&#xff0c;可以看出是根据字段term补齐数据中缺失的日期&#xff0c;term为连续日期的个数&#xff0c;当为12时&#xff0c;表明由2018-12-21到2019-01-02连续日期个数为12&#xff0c;当补齐日期后&#xff…

sklearn中的逻辑回归

目录 一.名为“回归”的分类器 二.逻辑回归的优点 三.sklearn中的逻辑回归 四.linear_model.LogisticRegression 五.penalty & C(正则化) 六.逻辑回归中的特征工程 1.业务选择 2.PCA和SVD一般不用 3.统计方法可以使用&#xff0c;但不是非常必要 4.高效的嵌入法e…

【vulhub漏洞复现】CVE-2013-4547 Nginx 文件名逻辑漏洞

一、漏洞详情影响版本 Nginx 0.8.41 ~ 1.4.3 / 1.5.0 ~ 1.5.7通过%00截断绕过后缀名的限制&#xff0c;使上传的php内容文件被解析执行。当Nginx得到一个用户请求时&#xff0c;首先对url进行解析&#xff0c;进行正则匹配&#xff0c;如果匹配到以.php后缀结尾的文件名&#x…

2022秋-2023-中科大-数字图像分析-期末考试试卷回忆版

今天晚上刚考完&#xff0c;心累&#xff0c;在这里继续授人以渔(仅供参考&#xff0c;切勿对着复习不看ppt&#xff0c;ppt一定要过两遍)。 注意:往年的经验贴&#xff0c;到此为止&#xff0c;全部作废&#xff0c;一个没考。千万不要只对着复习&#xff0c;SIFT没考&#x…

JavaScript(JS)

一、三种引入方式&#xff1a; 1、内部js 通过script标签嵌入到html里面 <script>alert(hello);</script> 2、外部js 写成一个单独的.js文件&#xff0c;让html引入进来 <script src"app.js"></script> 3、行内js 直接写到html内部 &…

Python爬虫——使用socket模块进行图片下载

Python爬虫——使用socket模块进行图片下载什么是socket爬虫的工作流程socket爬取图片为什么能用socket能下载图片socket下载图片和request下载图片的区别使用socket下载一张图片使用socket下载多张图片方法1方法2什么是socket Socket 是一种通信机制&#xff0c;用于实现网络…

AQS为什么用双向链表?

首先&#xff0c;在AQS中&#xff0c;等待队列是通过Node类来表示的&#xff0c;每个Node节点包含了等待线程的信息以及等待状态。下面是Node类的部分源码&#xff1a;static final class Node {// 等待状态volatile int waitStatus;// 前驱节点volatile Node prev;// 后继节点…

【AI绘图学习笔记】深度学习相关数学原理总结(持续更新)

如题&#xff0c;这是一篇深度学习相关数学原理总结文&#xff0c;由于深度学习中涉及到较多的概率论知识&#xff08;包括随机过程&#xff0c;信息论&#xff0c;概率与统计啥啥啥的)&#xff0c;而笔者概率知识储备属实不行&#xff0c;因此特意开一章来总结&#xff08;大部…

Jackson CVE-2017-17485 反序列化漏洞

0x00 前言 同CVE-2017-15095一样&#xff0c;是CVE-2017-7525黑名单绕过的漏洞&#xff0c;主要还是看一下绕过的调用链利用方式。 可以先看&#xff1a; Jackson 反序列化漏洞原理 或者直接看总结也可以&#xff1a; Jackson总结 涉及版本&#xff1a;2.8.10和2.9.x至2.…

leetcode_贪心算法

贪心算法相关题简单题目455.分发饼干1005.K次取反后最大化的数组和860.柠檬水找零序列问题376.摆动序列法一&#xff1a;贪心法法二&#xff1a;动态规划单调递增的数字简化版本有点难度53.最大子序和贪心算法动态规划134.加油站968.监控二叉树两个维度权衡问题分发糖果406.根据…

MATLAB——系统环境

MATLAB概述MATLAB的发展MATLAB:MATrix LABoratory1980年前后&#xff0c;Cleve Moler教授编写的Linpack 和Eispack的接口程序。1984年&#xff0c;MATLAB第1版(DOS版)1992年&#xff0c;MATLAB4.0版1994年&#xff0c;MATLAB 4.2版1997年&#xff0c;MATLAB 5.0版1999年&#x…

12-Trie树

Trie树&#xff08;又称字典树、单词查找树&#xff09;是一种树型的数据结构&#xff0c;常用于保存和查找字符串&#xff0c;是一种十分高效率的存储和检索方式。 Trie树原理 我们先假设有六个字符串需要存储&#xff1a;abc、abcd、abef、cfgh、bc、bcd。Trie树的存储原理…