Cómo Serialice Binary Tree

votos
23

Fui a una entrevista hoy donde me pidieron que serializar un árbol binario. He implementado un enfoque basado en matriz donde los hijos del nodo i (numeración en traversal orden de nivel) estaban en el * índice 2 i para el hijo izquierdo y 2 * i + 1 para el hijo derecho. El entrevistador parecía más o menos contento, pero me pregunto qué significa exactamente serializar? ¿Se refieren específicamente a la compresión del árbol para escribir en el disco, o si la serialización de un árbol también incluyen simplemente girando el árbol en una lista enlazada, por ejemplo. Además, ¿cómo hacemos para aplanar el árbol en una lista (por partida doble) ligado, y luego reconstruirlo? ¿Puede recrear la estructura exacta del árbol de la lista enlazada?

Publicado el 06/01/2011 a las 04:48
fuente por usuario
En otros idiomas...                            


10 respuestas

votos
6

Enfoque 1: hacer ambas cosas finde y Preordenes recorrido a searialize los datos de los árboles. En el uso de-serialización orden PRE y hacer BST el finde para formar adecuadamente el árbol.

Es necesario tanto por A -> B -> C se puede representar como pre-orden a pesar de que la estructura puede ser diferente.

Enfoque 2: Uso # como un centinela dondequiera que el hijo izquierdo o el derecho es nulo .....

Respondida el 23/02/2013 a las 20:49
fuente por usuario

votos
0

¿Qué hay de realizar un recorrido en orden y poner la llave raíz y todas las claves de nodos en un std :: lista u otro recipiente de su elección, que se aplana el árbol. A continuación, sólo tiene que serializar el std :: lista o recipiente de su elección utilizando la biblioteca de impulso.

La inversa es simple y después reconstruir el árbol utilizando inserción estándar a un árbol binario. Esto puede no ser del todo eficiente para un árbol muy grande, pero el tiempo de ejecución para convertir el árbol en un std :: lista es O (n) como máximo, y para reconstruir el árbol es O (log n) como máximo.

Estoy a punto de hacer esto para serializar un árbol acabo codificado en C ++ como estoy convirtiendo mi base de datos de Java a C ++.

Respondida el 12/03/2013 a las 18:59
fuente por usuario

votos
12

Todos esos artículos hablan sobre todo de la parte de serialización. La parte deserialización es ligeramente más difícil de hacer en una sola pasada.

He implementado una solución eficiente para la deserialización también.

Problema: serializar y deserializar un árbol binario que contiene los números positivos.

parte de serialización:

  1. Utilice 0 para representar nula.
  2. Serializar a la lista de números enteros utilizando recorrido en preorden.

parte deserialización:

  1. Toma en la lista de números enteros y utiliza método de ayuda recursivo para deserialización.
  2. deserializador Recursive devuelve un par (nodo BTNode, int nextIndexToRead) donde nodo es nodo de árbol construido hasta ahora, y nextIndexToRead es la posición de número siguiente para ser leído en la lista serializado de números.

A continuación se muestra el código en Java:

public final class BinaryTreeSerializer
{
    public static List<Integer> Serialize(BTNode root)
    {
        List<Integer> serializedNums = new ArrayList<Integer>();

        SerializeRecursively(root, serializedNums);

        return serializedNums;
    }

    private static void SerializeRecursively(BTNode node, List<Integer> nums)
    {
        if (node == null)
        {
            nums.add(0);
            return;
        }

        nums.add(node.data);
        SerializeRecursively(node.left, nums);
        SerializeRecursively(node.right, nums);
    }

    public static BTNode Deserialize(List<Integer> serializedNums)
    {
        Pair pair = DeserializeRecursively(serializedNums, 0);

        return pair.node;
    }

    private static Pair DeserializeRecursively(List<Integer> serializedNums, int start)
    {        
        int num = serializedNums.get(start);

        if (num == 0)
        {
            return new Pair(null, start + 1);
        }

        BTNode node = new BTNode(num);

        Pair p1 = DeserializeRecursively(serializedNums, start + 1);
        node.left = p1.node;

        Pair p2 = DeserializeRecursively(serializedNums, p1.startIndex);
        node.right = p2.node;

        return new Pair(node, p2.startIndex);
    }

    private static final class Pair
    {
        BTNode node;
        int startIndex;

        private Pair(BTNode node, int index)
        {
            this.node = node;
            this.startIndex = index;
        }
    }
}

public class BTNode 
{
    public int data;
    public BTNode left;
    public BTNode right;

    public BTNode(int data)
    {
        this.data = data;
    }
}
Respondida el 24/08/2013 a las 21:28
fuente por usuario

votos
0

La mejor manera es usar un char especiales (como # como comentario anterior mencionó) como centinela. Es mejor que la construcción de una matriz recorrido en orden y una matriz recorrido en preorden / orden posterior, tanto en complejidad espacio sabia y complejidad en cuanto a tiempo. también es manera más fácil de implementar.

lista enlazada no es un buen ajuste aquí desde el fin de reconstruir el árbol, que es mejor tener tiempo de acceso al elemento const

Respondida el 19/03/2014 a las 23:07
fuente por usuario

votos
2

El uso de pre recorrido orden, serializar árbol binario. Utilice el mismo recorrido en orden previo para deserializar árbol. Tenga cuidado con los casos extremos. Aquí nodos nulos están representados por "#"

public static String serialize(TreeNode root){
            StringBuilder sb = new StringBuilder();
            serialize(root, sb);
            return sb.toString();
        }

    private static void serialize(TreeNode node, StringBuilder sb){
        if (node == null) {
            sb.append("# ");
        } else {
            sb.append(node.val + " ");
            serialize(node.left, sb);
            serialize(node.right, sb);
        }
    }

    public static TreeNode deserialize(String s){
        if (s == null || s.length() == 0) return null;
        StringTokenizer st = new StringTokenizer(s, " ");
        return deserialize(st);
    }

    private static TreeNode deserialize(StringTokenizer st){
        if (!st.hasMoreTokens())
            return null;
        String val = st.nextToken();
        if (val.equals("#"))
            return null;
        TreeNode root = new TreeNode(Integer.parseInt(val));
        root.left = deserialize(st);
        root.right = deserialize(st);
        return root;
    } 
Respondida el 18/01/2016 a las 14:56
fuente por usuario

votos
0

He estado tratando de obtener la esencia de la misma. Así que aquí está mi aplicación Java. Como se ha mencionado, esto no es un árbol binario de una BST. Para la serialización, un recorrido en preorden parece estar funcionando más fácil (para una cadena con "NULO" para los nodos nulos). Por favor, compruebe el código de abajo con un ejemplo completo de llamadas de recursividad. Para deserializar, la cadena se convierte a un LinkedList donde remove (0) obtiene el elemento superior en un O (1) tiempo de funcionamiento. Por favor, vea también un ejemplo completo en los comentarios del código para deserializar. La esperanza de que ayude a alguien luchar menos que yo :) El tiempo total de funcionamiento para cada método (serializar y deserializar) es el mismo tiempo de funcionamiento de recorrido de árbol binario, es decir, O (n), donde n es el número de nodos (entradas) en el árbol

java.util.LinkedList importación; java.util.List importación;

SerDesBinTree public class {

public static class TreeEntry<T>{
    T element;
    TreeEntry<T> left;
    TreeEntry<T> right;
    public TreeEntry(T x){
        element = x;
        left = null;
        right = null;
    }
}

TreeEntry<T> root;
int size;
StringBuilder serSB = new StringBuilder();
List<String> desList = new LinkedList<>();

public SerDesBinTree(){
    root = null;
    size = 0;   
}

public void traverseInOrder(){
    traverseInOrder(this.root);
}

public void traverseInOrder(TreeEntry<T> node){
    if (node != null){
        traverseInOrder(node.left);
        System.out.println(node.element);
        traverseInOrder(node.right);
    }
}

public void serialize(){
    serialize(this.root);
}


/*
 *          1
 *         / \
 *        2   3
 *           /
 *          4 
 *        
 *        ser(1)                              
 *            serSB.append(1)                     serSB: 1
 *            ser(1.left)
 *            ser(1.right)
 *            |
 *            |
 *            ser(1.left=2)
 *                serSB.append(2)                 serSB: 1, 2
 *                ser(2.left)
 *                ser(2.right)
 *                |
 *                |
 *                ser(2.left=null)
 *                    serSB.append(NULL)          serSB: 1, 2, NULL
 *                    return
 *                |    
 *                ser(2.right=null)
 *                    serSB.append(NULL)          serSB: 1, 2, NULL, NULL
 *                    return
 *                    
 *             |
 *             ser(1.right=3)
 *                serSB.append(3)                 serSB: 1, 2, NULL, NULL, 3
 *                ser(3.left)
 *                ser(3.right)
 *                
 *                |
 *                ser(3.left=4)
 *                    serSB.append(4)             serSB: 1, 2, NULL, NULL, 3, 4
 *                    ser(4.left)
 *                    ser(4.right)
 *                    
 *                    |
 *                    ser(4.left=null)
 *                        serSB.append(NULL)      serSB: 1, 2, NULL, NULL, 3, 4, NULL
 *                        return
 *                        
 *                    ser(4.right=null)
 *                        serSB.append(NULL)      serSB: 1, 2, NULL, NULL, 3, 4, NULL, NULL
 *                        return
 *                        
 *                ser(3.right=null)
 *                    serSB.append(NULL)          serSB: 1, 2, NULL, NULL, 3, 4, NULL, NULL, NULL
 *                    return
 *        
 */
public void serialize(TreeEntry<T> node){
    // preorder traversal to build the string
    // in addition: NULL will be added (to make deserialize easy)
    // using StringBuilder to append O(1) as opposed to
    // String which is immutable O(n)
    if (node == null){
        serSB.append("NULL,");
        return;
    }

    serSB.append(node.element + ",");
    serialize(node.left);
    serialize(node.right);
}

public TreeEntry<T> deserialize(TreeEntry<T> newRoot){
    // convert the StringBuilder into a list
    // so we can do list.remove() for the first element in O(1) time

    String[] desArr = serSB.toString().split(",");

    for (String s : desArr){
        desList.add(s);
    }


    return deserialize(newRoot, desList);
}


/*
 *          1
 *         / \
 *        2   3
 *           /
 *          4 
 * 
 *        deser(root, list)                              list: 1, 2, NULL, NULL, 3, 4, NULL, NULL, NULL
 *            root = new TreeEntry(1)                    list: 2, NULL, NULL, 3, 4, NULL, NULL, NULL
 *            root.left = deser(root.left, list)  // **
 *            root.right = deser(root.right, list) // *-*
 *            return root // ^*^
 *            
 *            
 *      so far subtree
 *          1
 *         / \
 *      null  null
 *            
 *            deser(root.left, list)
 *                 root.left = new TreeEntry(2)          list: NULL, NULL, 3, 4, NULL, NULL, NULL
 *                 root.left.left = deser(root.left.left, list) // ***
 *                 root.left.right = deser(root.left.right, list)  // ****
 *                 return root.left // eventually return new TreeEntry(2) to ** above after the two calls are done
 *                 
 *           so far subtree
 *                 2
 *                / \
 *            null   null 
 *                 
 *                 deser(root.left.left, list)      
 *                     // won't go further down as the next in list is NULL
 *                      return null    // to ***                    list: NULL, 3, 4, NULL, NULL, NULL
 *                      
 *           so far subtree (same, just replacing null)
 *                 2
 *                / \
 *            null   null 
 *            
 *                 deser(root.left.right, list)
 *                     // won't go further down as the next in list is NULL
 *                      return null    // to ****                 list: 3, 4, NULL, NULL, NULL
 *                      
 *           so far subtree (same, just replacing null)
 *                 2
 *                / \
 *            null   null 
 *            
 *      
 *      so far subtree // as node 2 completely returns to ** above
 *          1
 *         / \
 *        2  null
 *       / \
 *   null   null
 *      
 *      
 *            deser(root.right, list)
 *                 root.right = new TreeEntry(3)                list: 4, NULL, NULL, NULL
 *                 root.right.left = deser(root.right.left, list) // *&*
 *                 root.right.right = deser(root.right.right, list)  // *---*
 *                 return root.right // eventually return to *-* above after the previous two calls are done
 *                 
 *           so far subtree
 *                 3
 *                / \
 *            null   null 
 *            
 *            
 *                 deser(root.right.left, list)
 *                      root.right.left = new TreeEntry(4)       list: NULL, NULL, NULL
 *                      root.right.left.left = deser(root.right.left.left, list) // *(*
 *                      root.right.left.right = deser(root.right.left.right, list) // *)*
 *                      return root.right.left // to *&*
 *                      
 *                  so far subtree
 *                       4
 *                      / \
 *                  null   null 
 *                    
 *                       deser(root.right.left.left, list)
 *                             // won't go further down as the next in list is NULL
 *                             return null // to *(*         list: NULL, NULL
 *                             
 *                  so far subtree (same, just replacing null)
 *                       4
 *                      / \
 *                  null   null 
 *                  
 *                       deser(root.right.left.right, list)
 *                             // won't go further down as the next in list is NULL
 *                             return null // to *)*         list: NULL
 *                             
 *                             
 *                  so far subtree (same, just replacing null)
 *                       4
 *                      / \
 *                  null   null 
 *                  
 *                  
 *           so far subtree
 *                 3
 *                / \
 *               4   null   
 *              / \
 *           null  null
 *                
 *                
 *                deser(root.right.right, list)
 *                        // won't go further down as the next in list is NULL
 *                       return null // to *---*    list: empty
 *                       
 *           so far subtree (same, just replacing null of the 3 right)
 *                 3
 *                / \
 *               4   null   
 *              / \
 *           null  null   
 *           
 *           
 *           now returning the subtree rooted at 3 to root.right in *-*
 *           
 *          1
 *         / \
 *        /   \
 *       /     \
 *      2       3
 *     / \     / \
 * null  null /   null
 *           /
 *          4
 *         / \
 *      null  null 
 *      
 *      
 *      finally, return root (the tree rooted at 1) // see ^*^ above
 *    
 */
public TreeEntry<T> deserialize(TreeEntry<T> node, List<String> desList){

    if (desList.size() == 0){
        return null;
    }

    String s = desList.remove(0); // efficient operation O(1)
    if (s.equals("NULL")){
        return null;
    }

    Integer sInt = Integer.parseInt(s);
    node = new TreeEntry<T>((T)sInt);

    node.left = deserialize(node.left, desList);
    node.right = deserialize(node.right, desList);

    return node;
}


public static void main(String[] args) {
    /*
     *          1
     *         / \
     *        2   3
     *           /
     *          4 
     *        
     */
    SerDesBinTree<Integer> tree = new SerDesBinTree<>();
    tree.root = new TreeEntry<Integer>(1);
    tree.root.left = new TreeEntry<Integer>(2);
    tree.root.right = new TreeEntry<Integer>(3);
    tree.root.right.left = new TreeEntry<Integer>(4);
    //tree.traverseInOrder();

    tree.serialize();
    //System.out.println(tree.serSB);

    tree.root = null;
    //tree.traverseInOrder();

    tree.root = tree.deserialize(tree.root);
    //tree.traverseInOrder();

    // deserialize into a new tree
    SerDesBinTree<Integer> newTree = new SerDesBinTree<>();
    newTree.root = tree.deserialize(newTree.root);
    newTree.traverseInOrder();


}

}

Respondida el 21/12/2017 a las 13:43
fuente por usuario

votos
-1

Aquí es otra forma de serialización árbol binario utilizando recorrido de fin de nivel (modificado). [Sólo copiar y pegar, funciona] Incluye todo tipo de árbol desequilibrado, equilibrada, sesgada a la derecha, a la izquierda sesgada.

class TreeNode():
    def __init__(self, val):
        self.val = val
        self.left = None
        self.right = None

def getHeight(root):
    if root == None:
        return 0
    return max(getHeight(root.left), getHeight(root.right)) + 1

treeArray = []

def levelOrderTraversal(root, level, numOfNodes):
    if level <= 0 and numOfNodes <=0:
        return

    numOfNodes -= 1

    if root != None and level == 1:
        treeArray.append(root.val)
    elif root == None and level == 1:
        treeArray.append("$")

    if root != None:
        levelOrderTraversal(root.left, level-1, numOfNodes)
        levelOrderTraversal(root.right, level-1, numOfNodes)
    else:
        levelOrderTraversal(root, level-1, numOfNodes)
        levelOrderTraversal(root, level-1, numOfNodes)



def treeToIntArray(root):
    h = getHeight(root)

    for i in range(1, h+1):
        levelOrderTraversal(root,i, i*2)

    return treeArray


def intArrayToTree():
    n = len(treeArray)

    treeArrayOfObjects = [0]*len(treeArray)
    for i in range(n):
        if treeArray[i] != "$":
            root = TreeNode(treeArray[i])
            treeArrayOfObjects[i] = root


    #Linking the child nodes
    for i in range(n):
        if treeArray[i] != "$":
            root = treeArrayOfObjects[i]
            if 2 * i + 1 < n:
                root.left = treeArrayOfObjects[2*i + 1]
            if 2 * i + 2 < n:
                root.right = treeArrayOfObjects[2*i + 2]
            treeArray[i] = root
    return treeArrayOfObjects[0]

"""
root = TreeNode(7)
root.left = TreeNode(3)
root.right = TreeNode(9)
root.left.left = TreeNode(1)
root.left.right = None
root.right.left = None
root.right.right = TreeNode(4)
"""
root = TreeNode(7)
root.right = TreeNode(9)
root.right.right = TreeNode(4)
root.right.right.right = TreeNode(5)

print treeToIntArray(root)
root = intArrayToTree()

print root.val
print root.right.val
print root.right.right.val
print root.right.right.right.val
Respondida el 28/11/2018 a las 00:14
fuente por usuario

votos
0

Aquí es una respuesta tardía en Python. Utiliza (profundidad primero) serialización orden previo y devuelve una lista de strings. Deserialización devuelve el árbol.

class Node:

    def __init__(self, val, left=None, right=None):

        self.val = val
        self.left = left
        self.right = right


# This method serializes the tree into a string

def serialize(root):

    vals = []

    def encode(node):

        vals.append(str(node.val))

        if node.left is not None:

            encode(node.left)
        else:
            vals.append("L")

        if node.right is not None:

            encode(node.right)
        else:
            vals.append("R")

    encode(root)

    print(vals)
    return vals

# This method deserializes the string back into the tree

def deserialize(string_list):

    def create_a_tree(sub_list):

        if sub_list[0] == 'L' or sub_list[0] == 'R':
            del sub_list[0]
            return

        parent = Node(sub_list[0])
        del sub_list[0]

        parent.left = create_a_tree(sub_list)

        parent.right = create_a_tree(sub_list)

        return parent

    if len(string_list) != 0:

        root_node = create_a_tree(string_list)
    else:
        print("ERROR - empty string!")
        return 0

    return root_node

Probar:

tree1 = Node('root', Node('left'), Node('right'))
t = deserialize(serialize(tree1))
print(str(t.right.val))
Respondida el 28/02/2019 a las 02:19
fuente por usuario

votos
-1

La serialización es el proceso de convertir una estructura de datos o un objeto en una secuencia de bits de modo que puede ser almacenado en una memoria intermedia de archivo o la memoria, o transmitida a través de un enlace de conexión de red a ser reconstruido más tarde en el mismo o en otro entorno informático.

Deserialización es el proceso de convertir la cadena de nuevo a la estructura de árbol original.

Concepto de serialización y deserialización es muy similar a lo que hace un compilador de código. Hay varias fases en todo el proceso de compilación, pero vamos a tratar de mantenerlo abstracto.

Dada una pieza de código, compilador rompe diferentes componentes bien definidos en tokens (por ejemplo, int es un contador, doble es otro contador, {es una ficha,} es otro contador, etc). [Enlace a una demostración del nivel abstracto de la compilación] [1].

Serialización: Nosotros usamos la lógica recorrido en preorden para serializar árbol en una cadena. Vamos a añadir "X" para denotar un puntero nulo / nodo en un árbol. Además, para mantener nuestra lógica deserialización en mente, tenemos que añadir "" después de cada valor de nodo en serie de modo que el proceso de deserialización puede acceder a cada valor de nodo split con "".

Leetcode enlace: https://leetcode.com/problems/serialize-and-deserialize-binary-tree/

Explicación de Espalda con espalda canal de Youtube SWE : https://www.youtube.com/watch?v=suj1ro8TIVY

For example:

You may serialize the following tree:

    1
   / \
  2   3
     / \
    4   5

as "[1,2,null,null,3,4,null,null,5,null,null,]"

 /**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Codec {

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {

        if(root == null)
            return "X,";

        String leftSerialized = serialize(root.left);
        String rightSerialized = serialize(root.right);

        return root.val + "," + leftSerialized + rightSerialized;
    }

    private TreeNode deserializeHelper(Queue<String> queue)
    {
        String nodeValue = queue.poll();

        if(nodeValue.equals("X"))
            return null;

        TreeNode newNode = new TreeNode(Integer.valueOf(nodeValue));

        newNode.left = deserializeHelper(queue);
        newNode.right = deserializeHelper(queue);

        return newNode;
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {

        Queue<String> queue = new LinkedList<>();
        queue.addAll(Arrays.asList(data.split(",")));

        return deserializeHelper(queue);
    }
}

//Codec object will be instantiated and called as such:
//Codec codec = new Codec();
//codec.deserialize(codec.serialize(root));
Respondida el 16/07/2019 a las 22:52
fuente por usuario

votos
0

No estoy usando pre-orden, pero estoy usando BFS. Esta es una pregunta de leetcode

La mayoría de la gente aplicación son incorrectos cuando se utiliza antes de la orden: el resultado esperado debería ser

"[1,2,3, null, null, 4,5]", pero en lugar de la mayoría de personas imprimir el resultado como "[1,2,3, null, null, 4,5, null, null]" ya que son sin contar los niveles.

Aquí está mi aplicación con el resultado correcto.

class Node(object):
    def __init__(self,data):
        self.left = None
        self.right = None
        self.data = data

def serialize(root):
        queue = [(root,0)]
        result = []
        max_level_with_value = 0
        while queue:
            (node,l) = queue.pop(0)
            if node:
                result.append((node.data,l))
                queue.extend([(node.left,l+1),
                              (node.right,l+1)
                              ])
                max_level_with_value = max(max_level_with_value,l)
            else:
                result.append(('null',l))
        filter_redundant(result,max_level_with_value)


def filter_redundant(result,max_level_with_value):
    for v,l in result:
        if l<= max_level_with_value:
            print(v)




root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.right.left = Node(4)
root.right.right = Node(5)
serialize(root)
Respondida el 09/10/2019 a las 02:02
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more