Wie man serialisiert Binary Tree

stimmen
23

Ich ging heute zu einem Interview, in dem ich gefragt wurde, einen binären Baum serialisiert. I implementiert ein Array-basierten Ansatz, bei dem die Kinder des Knotens i (Nummerierung in Ebene Ordnung traversal) in der 2 für das linke Kind * i Index waren und 2 * i + 1 für das rechte Kind. Der Interviewer schien mehr oder weniger zufrieden, aber ich frage mich, was serialize bedeutet das genau? Ist es speziell um den Baum zu Abflachung für das Schreiben auf die Festplatte beziehen, oder würde ein Baum umfassen auch die Serialisierung nur den Baum in einer verknüpften Liste drehen, sagen. Auch, wie würden wir gehen über den Baum in eine (doppelt) verkettete Liste Abflachung und Rekonstruieren es dann? Können Sie die genaue Struktur des Baumes aus der verknüpften Liste neu erstellen?

Veröffentlicht am 06/01/2011 um 04:48
quelle vom benutzer
In anderen Sprachen...                            


10 antworten

stimmen
6

Ansatz 1: Haben beide Inorder und Vorordnungsdurchquerung die Baumdaten searialize. Auf Deserialisierung Verwendung Pre-order und tut BST auf Inorder den Baum richtig zu bilden.

Sie müssen beide, weil A -> B -> C kann als Pre-Order dargestellt werden, obwohl die Struktur unterschiedlich sein kann.

Ansatz 2: Verwenden Sie # als Sentinel wo auch immer die linke oder rechte Kind null ist .....

Beantwortet am 23/02/2013 um 20:49
quelle vom benutzer

stimmen
0

Wie wäre es ein In-Order Traversal Durchführung und den Wurzelschlüssel und alle Knotenschlüssel in eine std :: Liste oder einem anderen Behälter Ihrer Wahl setzen, die den Baum abflacht. Dann serialisiert einfach die std :: Liste oder Container Ihrer Wahl der Boost-Bibliothek.

Das Umgekehrte ist einfach und dann den Baum unter Verwendung von Standard-Insertion in einen binären Baum neu aufzubauen. Dies kann nicht ganz für einen sehr großen Baum effizient sein, aber Laufzeit den Baum in eine std :: Liste zu konvertieren ist O (n) höchstens und den Baum neu zu erstellen ist O (log n) am meisten.

Ich bin dagegen zu tun, einen Baum zu serialisiert ich nur in C codierte up ++, wie ich meine Datenbank von Java nach C ++ bin Umwandlung.

Beantwortet am 12/03/2013 um 18:59
quelle vom benutzer

stimmen
12

All diese Artikel sprechen meist über die Serialisierung Teil. Der Deserialisierung Teil ist etwas heikel in einem Durchgang zu tun.

Ich habe eine effiziente Lösung für die Deserialisierung zu implementiert.

Problem: serialisiert und einen binären Baum mit positiven Zahlen Deserialize.

Serialisierung Teil:

  1. Verwenden Sie 0 auf null zu stellen.
  2. Serialisieren von ganzen Zahlen zur Liste Vorordnungsdurchquerung verwenden.

Deserialisierung Teil:

  1. Nimmt in der Liste von ganzen Zahlen und verwendet rekursive Hilfsmethode für die Deserialisierung.
  2. Recursive Deserialisierer gibt ein Paar (BTnode Knoten, int nextIndexToRead), in dem Knotenbaumknoten so weit ausgebildet ist, und ist nextIndexToRead Position der nächsten Nummer in der serialisierten Liste von Zahlen gelesen werden.

Unten ist der Code in 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;
    }
}
Beantwortet am 24/08/2013 um 21:28
quelle vom benutzer

stimmen
0

Der beste Weg ist, eine spezielle Zeichen (wie # als vorheriger Kommentar erwähnt) zu verwenden, wie Sentinel. Es ist besser als ein Inorder Traversal Array konstruieren und eine Preorder / Nachordnungsdurchquerung Array, sowohl im Raum Komplexität weise und Zeitkomplexität weise. es ist auch viel einfacher zu implementieren.

Verkettete Liste ist nicht eine gute Passform hier da, um den Baum zu rekonstruieren, haben Sie bessere const Element Zugriffszeit

Beantwortet am 19/03/2014 um 23:07
quelle vom benutzer

stimmen
2

Mit Pre Order Traversal, serialisiert Binary Tree. Verwenden Sie die gleiche Traversal Vorbestellen Baum deserialisieren. Seien Sie vorsichtig über den Rand Fällen. Hier null Knoten werden durch „#“ dargestellt

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;
    } 
Beantwortet am 18/01/2016 um 17:56
quelle vom benutzer

stimmen
0

Ich habe versucht, den Kern von ihm zu bekommen. So, hier ist meine Java-Implementierung. Wie bereits erwähnt, ist dies ein binärer Baum kein BST. Für die Serialisierung, scheint ein Vorordnungsdurchquerung zu werden leichter arbeiten (in einen String mit „NULL“ für null Knoten). Bitte überprüfen Sie den Code mit einem vollständigen Beispiel für Rekursion Anrufe. Für Deserialisieren wird die Zeichenfolge in eine VerketteteListe umgewandelt wo Entfernen (0), um das obere Element in einer O gets (1) Laufzeit. Bitte beachten Sie auch ein vollständiges Beispiel in den Kommentaren des Codes für Deserialisieren. Hoffe, das hilft jemand kämpft weniger als ich :) Die Gesamtlaufzeit für jede Methode hatte (Serialisierung und Deserialisierung) ist die gleiche Laufzeit für binären Baumdurchlauf, dh O (n), wobei n die Anzahl der Knoten (Einträge) im Baum

import java.util.LinkedList; import 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();


}

}

Beantwortet am 21/12/2017 um 16:43
quelle vom benutzer

stimmen
-1

Hier ist eine andere Art und Weise Binary Tree von Serialisierung mit (modifiziert) Ebene um Traversal. [Kopieren Sie einfach Paste, es funktioniert] fallen alle unausgewogen, ausgeglichen, rechts schräg links schräg Baum.

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
Beantwortet am 28/11/2018 um 00:14
quelle vom benutzer

stimmen
0

Hier ist eine späte Antwort in Python. Es verwendet (Tiefe zuerst) vorbestellbar Serialisierung und gibt eine Liste strings. Deserialisierung gibt den Baum.

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

Zu testen:

tree1 = Node('root', Node('left'), Node('right'))
t = deserialize(serialize(tree1))
print(str(t.right.val))
Beantwortet am 28/02/2019 um 02:19
quelle vom benutzer

stimmen
-1

Serialisierung ist der Prozess, eine Datenstruktur oder ein Objekt in eine Folge von Bits umzuwandeln, so dass es in einem Netzwerk-Link in einer Datei oder einem Speicher-Puffer oder übertragen gespeichert werden später rekonstruiert werden in demselben oder einem anderen Computer-Umgebung.

Deserialisierung ist der Prozess der Saite zurück zu der ursprünglichen Baumstruktur umgewandelt wird.

Konzept der Serialisierung und Deserialisierung ist sehr ähnlich zu dem, was ein Compiler Code tut. Es gibt mehrere Phasen im gesamten Übersetzungsvorgang, aber wir werden versuchen, abstrakt zu halten.

Bei einem gegebenen Stück Code, compiler verschiedene wohldefinierten Komponenten in Token bricht (zum Beispiel, int ist ein Token, doppelt ist ein weiterer Token, {ist ein Token,} ist ein weiterer Token, etc). [Link zu einer Demonstration der abstrakten Ebene der Kompilation] [1].

Serialisierung: Wir verwenden Vorordnungsdurchquerung Logik für Baum in einen String serialisiert. Wir fügen „X“ auf einen Null-Zeiger / Knoten in einem Baum zu bezeichnen. Darüber hinaus unsere Deserialisierung Logik im Auge zu behalten, müssen wir hinzufügen „“ nach jedem serialisierten Knotenwert, so dass die Deserialisierung jeden Knoten Wert Split mit Zugriff „“.

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

Erklärung von Rücken an Rücken SWE Youtube - Kanal : 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));
Beantwortet am 16/07/2019 um 22:52
quelle vom benutzer

stimmen
0

Ich verwende nicht vorbestellen , aber ich bin mit BFS. Dies ist eine Frage von leetcode

Die Mehrheit der Menschen Implementierung ist falsch, wenn jetzt vorbestellen mit: das erwartete Ergebnis sein sollte

"[1,2,3, null, null, 4,5]", sondern Mehrheit Leute drucken die Ausgabe als "[1,2,3, null, null, 4,5, null, null]", da sie nicht das Niveau zu zählen.

Hier ist meine Umsetzung mit dem richtigen Ergebnis.

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)
Beantwortet am 09/10/2019 um 02:02
quelle vom benutzer

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