Serialization and deserialization of binary tree

Posted by a1amattyj on Mon, 17 Jan 2022 14:08:09 +0100

Serialization and deserialization of binary tree

Title: Serialization of binary tree

"Programmer code interview guide" question 34 P107 difficulty: Shi ★☆☆☆

The serialization of binary tree is the process that binary tree is recorded as a file, and the deserialization of binary tree is the process of reconstructing the original binary tree through the file content.

Serialization process: first, assume that the result string of serialization is STR, and initially STR = "". If a null node is encountered, add "#!" at the end of str, "#" indicates that this node is empty and does not exist, "!" Indicates the end of a value; If you encounter a node that is not empty, assuming that the node value is 2, add "2!" to the end of str.

This book introduces two implementations of serialization and deserialization.

The first step is pre order traversal. The serialization process is as follows:

public String serialByPre(Node head) {
    if (head == null) {
        return "#!";
    }
    String res = head.value + "!";
    res += serialByPre(head.left);
    res += serialByPre(head.right);
    return res;
}

It can be seen that the process is very simple, which is basically a slight modification on the basis of preorder traversal recursion. Note the use of return values.

Then the deserialization process:

public Node reconByPreString(String preStr) {
    String[] values = preStr.split("!");
    Queue<String> queue = new LinkedList<String>();
    for (int i = 0; i != values.length; i++) {
        queue.offer(values[i]);
    }
    return reconPreOrder(queue);
}

public Node reconPreOrder(Queue<String> queue) {
    String value = queue.poll();
    if (value.equals("#")) {
        return null;
    }
    Node head = new Node(Integer.valueOf(value));
    head.left = reconPreOrder(queue);
    head.right = reconPreOrder(queue);
    return head;
}

It is realized through queue + recursion. First, insert all nodes into the queue one by one, and then take out the queue elements one by one. At the same time, select to return null by judging "#" or assign a value to the left child or right child of the current node.

Note that you first need to pass "!" Disassemble the original string into a string array. At the same time, the queue in the recursive inner layer pops up elements, and the queue in the outer layer also changes accordingly. (the value passed is a reference, the content has been modified, and all variables accessed for the reference are the same content)

The second is sequence traversal. Both serialization and deserialization use queue structure.

Serialization:

public String serialByLevel(Node head) {
    if (head == null) {
        return "#!";
    }
    String res = head.value + "!";
    Queue<Node> queue = new LinkedList<Node>();
    queue.offer(head);
    while (!queue.isEmpty()) {
        head = queue.poll();
        if (head.left != null) {
            res += head.left.value + "!";
            queue.offer(head.left);
        } else {
            res += "#!";
        }
        if (head.right != null) {
            res += head.right.value + "!";
            queue.offer(head.right);
        } else {
            res += "#!";
        }
    }
    return res;
}

Deserialization:

public Node reconByLevelString(String levelStr) {
    String[] values = levelStr.split("!");
    int index = 0;
    Node head = generateNodeByString(values[index++]);
    Queue<Node> queue = new LinkedList<Node>();
    if (head != null) {
        queue.offer(head);
    }
    Node node = null;
    while (!queue.isEmpty()) {
        node = queue.poll();
        node.left = generateNodeByString(values[index++]);
        node.right = generateNodeByString(values[index++]);
        if (node.left != null) {
            queue.offer(node.left);
        }
        if (node.right != null) {
            queue.offer(node.right);
        }
    }
    return head;
}

public Node generateNodeByString(String val) {
    if (val.equals("#")) {
        return null;
    }
    return new Node(Integer.valueOf(val));
}

For the deserialization of the two traversals, in fact, the corresponding traversals are redone. When "#" is encountered, a null node is generated. The pre sequence traversal stops the process of generating subsequent subtrees, and the sequence traversal does not put the null node in the queue.

The details of the algorithm will not be repeated. See the code for understanding (⊙ o ⊙)

Topics: Algorithm