算法练习(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;
    }
} 
posted @ 2021-11-02 23:23  菩提树下的杨过  阅读(76)  评论(0编辑  收藏  举报