zoukankan      html  css  js  c++  java
  • 算法练习(15)-设计1个二叉树的序列化与反序列化实现?

    思路: 二叉树的各种顺序中,随便挑1种,遍历每个节点, 拼装出1个字符串即可实现序列化。要注意的是, 空节点也需要, 可以找一个特殊符号比如#表示。 反序列化则是相反的过程,解析该字符串即可。

    这里用层序遍历来实现一把:

    序列化代码:

    public static String serial(TreeNode node) {
        StringBuilder sb = new StringBuilder();
        if (node == null) {
            sb.append("#_");
            return sb.toString();
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(node);
        while (!queue.isEmpty()) {
            TreeNode n = queue.poll();
            sb.append(n == null ? "#_" : n.val + "_");
            if (n != null) {
                queue.add(n.left);
                queue.add(n.right);
            }
        }
        //注:0位置占位不用, 方便后面反序列化
        return "*_" + sb.toString();
    }
    

    假设有一颗树:

    把空节点补全后,如下图:

    序列化后为 *_1_2_3_4_5_#_7_#_#_#_#_#_#_ 按"_"拆分成String[]后,就变成了二叉树的数组存储 , 如果根节点的下标从1算起,每个元素的左孩子索引为2*i,右孩子索引为2*i+1 ,它的父节点索引为i/2 (这也是为啥第0个元素要用*占位的原因),根据这个特性, 很容易可以写反序列化的代码:

    public static TreeNode deSerial(String str) {
        if (str == null || str.length() <= 0) {
            return null;
        }
        String[] arr = str.split("_");
        TreeNode root = new TreeNode(Integer.parseInt(arr[1]));
        Map<Integer, TreeNode> parentMap = new HashMap<>();
        parentMap.put(1, root);
        int curr = 1;
        while (curr < (arr.length >> 1)) {
            int leftIndex = curr << 1;
            int rightIndex = (curr << 1) + 1;
            String leftVal = arr[leftIndex];
            String rightVal = arr[rightIndex];
            if (!"#".equals(leftVal)) {
                TreeNode leftNode = new TreeNode(Integer.parseInt(leftVal));
                int parentIndex = leftIndex >> 1;
                parentMap.get(parentIndex).left = leftNode;
                parentMap.put(leftIndex, leftNode);
            }
            if (!"#".equals(rightVal)) {
                TreeNode rightNode = new TreeNode(Integer.parseInt(rightVal));
                int parentIndex = rightIndex >> 1;
                parentMap.get(parentIndex).right = rightNode;
                parentMap.put(rightIndex, rightNode);
            }
            curr++;
        }
        return root;
    }
    

    当然, 也可以换成先序遍历实现, 序列化后为: 4_2_1_#_#_3_#_#_6_5_#_#_7_#_#_

    /**
     * 先序遍历序列化二叉树
     *
     * @param node
     * @return
     */
    public static String serial(TreeNode node) {
        StringBuilder sb = new StringBuilder();
        if (node == null) {
            sb.append("#_");
            return sb.toString();
        }
        sb.append(node.val + "_");
        sb.append(serial(node.left));
        sb.append(serial(node.right));
        return sb.toString();
    }
    
    private static int curr = -1;
    
    /**
     * 先序遍历反序列化
     *
     * @param str
     * @return
     */
    public static TreeNode deSerial(String str) {
        if (str == null) {
            return null;
        }
        curr = -1;
        String[] arr = str.split("_");
        return process(arr);
    }
    
    /**
     * 从左至右,每次取1个元素,按头-左-右的顺序构建
     *
     * @param arr
     * @return
     */
    private static TreeNode process(String[] arr) {
        curr++;
        if (!"#".equals(arr[curr])) {
            TreeNode node = new TreeNode(Integer.parseInt(arr[curr]));
            node.left = process(arr);
            node.right = process(arr);
            return node;
        } else {
            return null;
        }
    } 
    作者:菩提树下的杨过
    出处:http://yjmyzz.cnblogs.com
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    linq to sql的性能和reader相比只是差一点点吗
    Win11删除右键菜单open in windows Terminal
    jdk1.8
    mvcc read view
    javascript 跨域双向通信方案,通过postMessage和window.name实现
    [原创]如何加载动态库、获取方法委托、卸载动态库
    awseks创建与使用
    aiops 调研
    consul调研
    机器学习调研
  • 原文地址:https://www.cnblogs.com/yjmyzz/p/15500934.html
Copyright © 2011-2022 走看看