7.Binary Tree Serialization-二叉树的序列化和反序列化(中等题)

本文介绍了一种二叉树的序列化和反序列化的算法实现,通过层序遍历方式将二叉树转换为字符串形式,并能够从字符串还原成二叉树结构。该方法使用队列辅助完成节点的遍历。

二叉树的序列化和反序列化

  1. 题目

    设计一个算法,并编写代码来序列化和反序列化二叉树。将树写入一个文件被称为“序列化”,读取文件后重建同样的二叉树被称为“反序列化”。
    如何反序列化或序列化二叉树是没有限制的,你只需要确保可以将二叉树序列化为一个字符串,并且可以将字符串反序列化为原来的树结构。

  2. 样例

    给出一个测试数据样例, 二叉树{3,9,20,#,#,15,7},表示如下的树结构:
    这里写图片描述
    我们的数据是进行BFS遍历得到的。当你测试结果wrong answer时,你可以作为输入调试你的代码。
    你可以采用其他的方法进行序列化和反序列化。

  3. 题解

本题的序列化和反序列化都是二叉树的层序遍历问题,使用队列解决。先将头结点入列,将节点值序列化,再将其出列的同时检查其左右子节点是否为null,如不为null则入列,否则仅序列化即可,直至遍历完毕。

/**
 * Definition of TreeNode:
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left, right;
 *     public TreeNode(int val) {
 *         this.val = val;
 *         this.left = this.right = null;
 *     }
 * }
 */
class Solution {
    /**
     * This method will be invoked first, you should design your own algorithm 
     * to serialize a binary tree which denote by a root node to a string which
     * can be easily deserialized by your own "deserialize" method later.
     */
    public String serialize(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        StringBuilder sb = new StringBuilder("");
        if (root == null)
        {
            return sb.toString();
        }
        queue.add(root);
        sb.append(String.valueOf(root.val) + ",");
        while (!queue.isEmpty())
        {
            TreeNode t = queue.poll();
            if (t.left != null)
            {
                queue.add(t.left);
            }
            sb.append(t.left == null ? "#," : String.valueOf(t.left.val) + ",");
            if (t.right != null)
            {
                queue.add(t.right);
            }
            sb.append(t.right == null ? "#" : String.valueOf(t.right.val));
            if (!queue.isEmpty())
            {
                sb.append(",");
            }
        }
        return sb.toString();
    }

    /**
     * This method will be invoked second, the argument data is what exactly
     * you serialized at method "serialize", that means the data is not given by
     * system, it's given by your own serialize method. So the format of data is
     * designed by yourself, and deserialize it here as you serialize it in 
     * "serialize" method.
     */
    public TreeNode deserialize(String data) {
        if (data.equals(""))
        {
            return null;
        }
        String[] nodeArr = data.split(",");
        TreeNode root = new TreeNode(Integer.valueOf(nodeArr[0]));
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.add(root);
        int index = 0;
        while (!queue.isEmpty())
        {
            TreeNode t = queue.poll();
            if (++index < nodeArr.length && !nodeArr[index].equals("#"))
            {
                t.left = new TreeNode(Integer.valueOf(nodeArr[index]));
                queue.add(t.left);
            }
            if (++index < nodeArr.length && !nodeArr[index].equals("#"))
            {
                t.right = new TreeNode(Integer.valueOf(nodeArr[index]));
                queue.add(t.right);
            }
        }

        return root;
    }
}

Last Update 2016.9.20

Java是一种具备卓越性能与广泛平台适应性的高级程序设计语言,最初由Sun Microsystems(现属Oracle公司)的James Gosling及其团队于1995年正式发布。该语言在设计上追求简洁性、稳定性、可移植性以及并发处理能力,同时具备动态执行特性。其核心特征与显著优点可归纳如下: **平台无关性**:遵循“一次编写,随处运行”的理念,Java编写的程序能够在多种操作系统与硬件环境中执行,无需针对不同平台进行修改。这一特性主要依赖于Java虚拟机(JVM)的实现,JVM作为程序与底层系统之间的中间层,负责解释并执行编译后的字节码。 **面向对象范式**:Java全面贯彻面向对象的设计原则,提供对封装、继承、多态等机制的完整支持。这种设计方式有助于构建结构清晰、模块独立的代码,提升软件的可维护性与扩展性。 **并发编程支持**:语言层面集成了多线程处理能力,允许开发者构建能够同时执行多项任务的应用程序。这一特性尤其适用于需要高并发处理的场景,例如服务器端软件、网络服务及大规模分布式系统。 **自动内存管理**:通过内置的垃圾回收机制,Java运行时环境能够自动识别并释放不再使用的对象所占用的内存空间。这不仅降低了开发者在内存管理方面的工作负担,也有效减少了因手动管理内存可能引发的内存泄漏问。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
<think>我们要求使用System.Runtime.Serialization.Formatters.Binary对数组进行序列化反序列化。 根据引用[2]引用[3]中的示例,我们可以总结出如下步骤: 1. 创建BinaryFormatter对象 2. 使用文件流或内存流 3. 调用Serialize方法将数组序列化到流中 4. 调用Deserialize方法从流中反序列化得到数组 注意:数组类型本身是可序列化的,因为它是System.Array的派生类型,而System.Array标记了[Serializable]特性。 下面我们将分别展示两种方式: 方式一:序列化到文件(适合持久化存储) 方式二:序列化到内存流(适合网络传输或进程间通信) 同时,我们也会展示如何处理基本数据类型数组自定义对象数组。 另外,根据引用[5],我们也可以看到如何将序列化的结果转换为byte[],这对于内存中处理非常有用。 注意:.NET 5.0及以上版本中,BinaryFormatter已被标记为过时,因此在使用时要注意环境。 示例代码将包括: 1. 整型数组的序列化反序列化(文件方式) 2. 字符串数组的序列化反序列化(内存流方式,并转换为字节数组) 3. 自定义对象数组的序列化反序列化(文件方式) 自定义对象需要标记[Serializable]特性。 我们首先定义自定义对象类(如Person)用于示例。 </think>以下是使用 `System.Runtime.Serialization.Formatters.Binary` 进行数组序列化反序列化的完整方法及示例代码: ### 数组序列化核心步骤 ```mermaid graph TD A[创建数组对象] --> B[创建文件流或内存流] B --> C[实例化BinaryFormatter] C --> D[调用Serialize写入流] D --> E[保存为文件或字节数组] ``` ### 基本类型数组示例(整型数组) ```csharp using System; using System.IO; using System.Runtime.Serialization.Formatters.Binary; class ArraySerializationDemo { static void Main() { int[] numbers = { 10, 20, 30, 40, 50 }; // 序列化到文件 BinarySerializeToFile("numbers.dat", numbers); // 从文件反序列化 int[] deserializedNumbers = BinaryDeserializeFromFile<int[]>("numbers.dat"); Console.WriteLine("反序列化结果:"); foreach (int num in deserializedNumbers) { Console.Write(num + " "); } } // 序列化到文件 static void BinarySerializeToFile<T>(string filePath, T obj) { using (FileStream fs = new FileStream(filePath, FileMode.Create)) { new BinaryFormatter().Serialize(fs, obj); } } // 从文件反序列化 static T BinaryDeserializeFromFile<T>(string filePath) { using (FileStream fs = new FileStream(filePath, FileMode.Open)) { return (T)new BinaryFormatter().Deserialize(fs); } } } ``` ### 内存流序列化(字节数组转换) ```csharp // 序列化数组到字节数组 static byte[] SerializeArrayToBytes<T>(T[] array) { using (MemoryStream ms = new MemoryStream()) { new BinaryFormatter().Serialize(ms, array); return ms.ToArray(); // 返回二进制数据[^3] } } // 从字节数组反序列化 static T[] DeserializeArrayFromBytes<T>(byte[] data) { using (MemoryStream ms = new MemoryStream(data)) { return (T[])new BinaryFormatter().Deserialize(ms); } } // 使用示例: string[] fruits = { "苹果", "香蕉", "橙子" }; // 序列化为字节数组 byte[] fruitData = SerializeArrayToBytes(fruits); // 反序列化还原数组 string[] restoredFruits = DeserializeArrayFromBytes<string>(fruitData); ``` ### 自定义对象数组示例 ```csharp [Serializable] public class Product { public int Id { get; set; } public string Name { get; set; } public decimal Price { get; set; } } // 创建并序列化对象数组 Product[] products = { new Product { Id = 1, Name = "键盘", Price = 299.99m }, new Product { Id = 2, Name = "鼠标", Price = 149.99m } }; BinarySerializeToFile("products.dat", products); // 反序列化对象数组 Product[] loadedProducts = BinaryDeserializeFromFile<Product[]>("products.dat"); ``` ### 关键注意事项 1. **类型兼容性要求** - 基本类型数组(`int[]`, `string[]` 等)可直接序列化 - 自定义对象数组要求元素类型标记 `[Serializable]` 特性[^1] - 数组维度支持:一维/多维数组均可序列化 2. **性能优化** ```csharp // 预分配内存流大小提升性能(适用于大型数组) byte[] SerializeLargeArray<T>(T[] array) { // 预估初始大小 = 数组长度 * 预估元素大小 + 头部信息 int estimatedSize = array.Length * 128 + 1024; using (MemoryStream ms = new MemoryStream(estimatedSize)) { new BinaryFormatter().Serialize(ms, array); return ms.ToArray(); } } ``` 3. **异常处理** ```csharp try { var data = DeserializeArrayFromBytes<int>(byteArray); } catch (SerializationException ex) { Console.WriteLine($"反序列化失败: {ex.Message}"); } catch (InvalidCastException ex) { Console.WriteLine($"类型转换错误: {ex.Message}"); } ``` ### 应用场景建议 1. **游戏开发**:保存游戏关卡中的对象位置数组 2. **科学计算**:传输大型数值计算数据集 3. **配置存储**:保存用户自定义的对象集合 4. **网络通信**:高效传输结构化数据包(相比JSON体积减少约40%)[^3]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值