序列化是什么?为什么需要序列化?
前言:
(1)进程想要运行,就要向操作系统申请内存空间,进程对数据的所有操作都是在内存空间中完成的。内存中有一部分数据很重要,我们希望将这些数据存储到磁盘中,就算进程被杀死、机器重启仍能找到这些数据,这时候就需要使用到序列化。
(2)以redis执行命令的流程为例,客户端(进程)想要执行一条命令,首先需要将命令封装(序列化)成redis协议指定的数据格式,随后基于socket将数据发送给redis服务(进程);redis服务收到数据后,将数据解析成具体的命令(反序列化),执行命令后,将执行结果封装成redis协议指定的数据格式(序列化)返回给客户端
序列化指将数据转化成某种可以存储或传输形式的过程。无论是将内存中的数据迁移到磁盘,还是进程间的通信都需要使用到序列化。
题目:297. 二叉树的序列化与反序列化 - 力扣(LeetCode)
题目描述:
解决方案:
题目需要我们既可以将一棵二叉树转化成字符串的形式(序列化),又可以将字符串还原成一颗二叉树(反序列化)。
(1)先序:
public class Codec {// Encodes a tree to a single string.public String serialize(TreeNode root) {StringBuilder sb = new StringBuilder();String result = serialize(root, sb);return result;}private static String serialize(TreeNode root,StringBuilder sb){//空节点用$符号填充if(root == null)sb.append("$,");else{//非空节点则添加节点值sb.append(root.val + ",");serialize(root.left,sb);serialize(root.right,sb);}return sb.toString();}// Decodes your encoded data to tree.public TreeNode deserialize(String data) {//获取元素是二叉树结点的字符串数组String [] val = data.split(",");//从字符串数组的索引0开始初始化二叉树cnt = 0;TreeNode root = deserialize(val);return root;}//cnt:即将被创建的结点public static int cnt;private static TreeNode deserialize(String [] val){String value = val[cnt++];if (value.equals("$")){//碰到$占位符,说明是空结点,直接返回nullreturn null;}else{//不是$,则创建结点TreeNode node = new TreeNode(Integer.parseInt(value));//将递归结果作为左、右子树node.left = deserialize(val);node.right = deserialize(val);//返回当前结点return node;}}
}
原理:
(1)序列化:以先序遍历的方式访问二叉树的每一个结点,并将结点值序列化成字符串,如果碰到空结点,就用$表示,最后会得到一个由"结点值"、"$"、","等三种字符组成的字符串。
(2)反序列化:将字符串通过split分割成一个字符串数组val,基于val数组和cnt指针以先序的顺序重建字符串。
(2)层序:配合队列逐层序列化、反序列化二叉树。
public class Codec {public static int MAX = 10001;//用数组模拟队列,层序遍历整棵树public static TreeNode [] q = new TreeNode[MAX];//head == tail时,队列的size == 0public static int head,tail;// Encodes a tree to a single string.public String serialize(TreeNode root) {StringBuilder sb = new StringBuilder();if(root != null){//初始化队列大小head = tail = 0;//序列化当前结点sb.append(root.val + ",");//头结点入队q[tail++] = root;//循环结束条件:队列为空while(head < tail){TreeNode node = q[head++];if(node.left != null){//子节点不为null//既序列化结点,又让结点入队sb.append(node.left.val +",");q[tail++] = node.left;}else{//子节点为null//用$填充,不让结点入队sb.append("$,");}if(node.right != null){sb.append(node.right.val +",");q[tail++] = node.right;}else{sb.append("$,"); }}}return sb.toString();}// Decodes your encoded data to tree.public TreeNode deserialize(String data) {//有可能是空树,空树直接返回nullif(data.equals(""))return null;//分割字符String [] val = data.split(",");//cnt变量从索引0开始遍历val字符串数组,并在遍历过程中创建结点int cnt = 0;//创建根节点TreeNode root = createNode(val[cnt++]);//重置head、tail指针head = tail = 0;q[tail++] = root;while(head < tail){TreeNode node = q[head++];node.left = createNode(val[cnt++]);node.right = createNode(val[cnt++]);//左、右孩子不是空结点就入队//因为要初始化它们的左、右孩子if(node.left != null){q[tail++] = node.left;}if(node.right != null){q[tail++] = node.right;}}return root;}private TreeNode createNode(String val){//val == "$",说明是空结点,返回null//val != "$",不是空结点,创建结点并返回return val.equals("$") ? null : new TreeNode(Integer.parseInt(val));}
}
层序序列化图解:
层序反序列化图解:
以上就是本文的全部内容,有什么错误的地方请评论区指正,如果你觉得本文让你有所收获,不妨点个赞!