Comment faire pour sérialiser Binary Tree

voix
23

Je suis allé à une interview aujourd'hui où on m'a demandé de sérialiser un arbre binaire. Je mis en œuvre une approche basée sur la baie où les enfants du noeud i (numérotation au niveau d'ordre traversal) étaient au 2 * indice i pour l'enfant gauche et 2 * i + 1 pour l'enfant à droite. L'intervieweur semblait plus ou moins heureux, mais je me demande ce que serialize signifie exactement? Est-il plus particulièrement à l'aplatissement concernent l'arbre pour l'écriture sur le disque, ou si la sérialisation d'un arbre comprennent aussi simplement tourner l'arbre dans une liste chaînée, par exemple. De plus, comment pourrions-nous aller sur aplatir l'arbre dans une liste chaînée (doublement), puis le reconstruire? Pouvez-vous recréer la structure exacte de l'arbre de la liste chaînée?

Créé 06/01/2011 à 04:48
source utilisateur
Dans d'autres langues...                            


10 réponses

voix
6

Approche 1: Faire les deux Inorder et Précommande traversal pour searialize les données sur les arbres. Lors de l'utilisation de-sérialisation précommande et ne BST sur Inorder pour former correctement l'arbre.

Vous avez besoin à la fois parce que A -> B -> C peut être représenté comme pré-commande, même si la structure peut être différente.

Approche 2: Utiliser # comme sentinelle whereever l'enfant gauche ou à droite est nul .....

Créé 23/02/2013 à 20:49
source utilisateur

voix
0

Que diriez-vous effectuer une commande traversal et de mettre la clé racine et toutes les clés de nœud dans un std :: liste ou un autre récipient de votre choix qui aplatit l'arbre. Ensuite, sérialisation simplement le std :: liste ou d'un conteneur de votre choix à l'aide de la bibliothèque Boost.

L'inverse est simple, puis reconstruire l'arbre en utilisant l'insertion standard à un arbre binaire. Cela peut ne pas être tout à fait efficace pour un très grand arbre, mais l'exécution pour convertir l'arbre en std :: liste est O (n) au plus et de reconstruire l'arbre est O (log n) au plus.

Je suis sur le point de le faire pour sérialiser un arbre que je viens codé en C ++ comme je suis en train de convertir ma base de données Java en C ++.

Créé 12/03/2013 à 18:59
source utilisateur

voix
12

Tous ces articles parlent surtout de la part de sérialisation. La partie de désérialisation est un peu difficile à faire en une seule passe.

J'ai mis en place une solution efficace pour désérialisation aussi.

Problème: sérialisation et la désérialisation un arbre binaire contenant des nombres positifs.

partie sérialisation:

  1. Utilisez 0 pour représenter null.
  2. Sérialisation à la liste des entiers à l'aide de pré-commande traversal.

partie Désérialisation:

  1. Prend la liste des entiers et utilise la méthode d'aide récursive pour désérialisation.
  2. Récursif désérialiseur renvoie une paire (noeud BTNode, int nextIndexToRead) lorsque le noeud est le noeud de l'arbre construit à ce jour, et nextIndexToRead est la position du numéro suivant à lire dans la liste des numéros sérialisés.

Voici le code 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;
    }
}
Créé 24/08/2013 à 21:28
source utilisateur

voix
0

La meilleure façon est d'utiliser un caractère spécial (comme # comme commentaire précédent mentionné) comme sentinelle. Il vaut mieux que de construire un tableau de parcours infixe et un pré-commande / postorder tableau traversal, aussi bien dans la complexité de l'espace sage et la complexité du temps sage. il est également plus facile à mettre en œuvre.

liste chaînée est pas un bon ajustement ici car pour reconstruire l'arbre, il vaut mieux avoir le temps d'accès des éléments const

Créé 19/03/2014 à 23:07
source utilisateur

voix
2

Utilisation de pré commande traversal, sérialisation arbre binaire. Utilisez le même pré commande traversal désérialiser arbre. Faites attention sur les cas de pointe. Ici, les noeuds nuls sont représentés par « # »

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;
    } 
Créé 18/01/2016 à 17:56
source utilisateur

voix
0

J'ai essayé d'obtenir l'essentiel de celui-ci. Voici donc mon implémentation de Java. Comme mentionné précédemment, c'est un arbre binaire et non un BST. Pour sérialisation, un parcours de l'semble fonctionner plus facile (à une chaîne avec « NULL » pour les noeuds nuls). S'il vous plaît vérifier le code ci-dessous un exemple complet des appels récursifs. Pour désérialisation, la chaîne est converti en un LinkedList où remove (0) reçoit l'élément supérieur dans un joint (1) temps de fonctionnement. S'il vous plaît voir aussi un exemple complet dans les commentaires du code pour désérialisation. L'espoir qui va aider quelqu'un lutte moins que moi :) Le temps de fonctionnement global pour chaque méthode (sérialisation et la désérialisation) est en même temps de course pour traversal arbre binaire, c.-à-O (n) où n est le nombre de noeuds (entrées) dans l'arbre

importation java.util.LinkedList; importation java.util.List;

public class {SerDesBinTree

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();


}

}

Créé 21/12/2017 à 16:43
source utilisateur

voix
-1

Voici une autre façon de sérialisation arbre binaire utilisant l'ordre de niveau (modifié) traversal. [Il suffit de copier coller, ça marche] Couvre tout déséquilibre, équilibré, déviées vers la droite, à gauche arbre biaisé.

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
Créé 28/11/2018 à 00:14
source utilisateur

voix
0

Voici une réponse tardive en Python. Il utilise (profondeur d' abord) sérialisation pré - commande et retourne une liste de strings. Désérialisation retourne l'arbre.

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

Tester:

tree1 = Node('root', Node('left'), Node('right'))
t = deserialize(serialize(tree1))
print(str(t.right.val))
Créé 28/02/2019 à 02:19
source utilisateur

voix
-1

La sérialisation est le processus de conversion d'une structure de données ou un objet dans une séquence de bits de sorte qu'il peut être stocké dans un fichier ou un tampon mémoire ou transmise sur une liaison de connexion de réseau à reconstruire plus tard dans le même ou un autre environnement informatique.

Désérialisation est le processus consistant à convertir la chaîne de retour à l'arborescence d'origine.

Le concept de sérialisation et désérialisation est très similaire à ce qu'un compilateur fait à coder. Il y a plusieurs phases dans l'ensemble du processus de compilation, mais nous allons essayer de le garder abstrait.

Étant donné un morceau de code, compilateur casse différents composants bien définis en jetons (par exemple, int est un jeton, double est un autre jeton, {est un jeton,} est un autre jeton, etc.). [Lien vers une démonstration du niveau de la compilation abstraite] [1].

Sérialisation: Nous utilisons la logique de pré-commande traversal pour arbre sérialisation à une chaîne. Nous allons ajouter « X » pour désigner un pointeur / nœud nul dans un arbre. De plus, pour garder notre logique de désérialisation à l'esprit, nous devons ajouter « » après chaque valeur de noeud sérialisé afin que le processus de désérialisation peut accéder à chaque fraction de la valeur de nœud avec « ».

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

Explication par Back To Back SWE chaîne Youtube : 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));
Créé 16/07/2019 à 22:52
source utilisateur

voix
0

Je n'utilise pas pré-commande , mais je me sers BFS. Ceci est une question de leetcode

La majorité des personnes sont mise en œuvre incorrecte lors de l'utilisation de précommande: le résultat attendu devrait être

"[1,2,3, null, null, 4,5]", mais la majorité des gens imprimer la sortie comme "[1,2,3, null, null, 4,5, null, null]" car ils sont sans compter les niveaux.

Voici ma mise en œuvre avec le bon résultat.

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)
Créé 09/10/2019 à 02:02
source utilisateur

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