Jak Serializovat binární strom

hlasů
23

Šel jsem na pohovor dnes, kdy jsem byl požádán, aby serializaci binární strom. Jsem implementoval přístup je založená na poli, kde se děti i uzlu (číslování v úrovni řádu průchod) byly při * indexu i na 2 pro levou dítě a 2 x i + 1 pro pravou dítě. Tazatel se zdálo více či méně potěšen, ale já jsem přemýšlel, co serialize přesně znamená? Znamená to konkrétně týkají zploštění strom pro zápis na disk, nebo by serializaci strom také zahrnují jen otáčení strom do propojeného seznamu, říkají. Také, jak bychom jít o zploštění strom do (dvakrát) propojeného seznamu, a pak rekonstruovat ji? Můžete vytvořit naprosto stejnou strukturu stromu z propojeného seznamu?

Položena 06/01/2011 v 04:48
zdroj uživatelem
V jiných jazycích...                            


10 odpovědí

hlasů
6

Přístup 1: dělat obojí nezbytného a předobjednávku traversal na searialize dat stromu. Na použití de-serialization Pre-order a dělat BST na nezbytného správně tvořit strom.

Musíte jednak proto, že A -> B -> C může být reprezentován jako pre-order, i když struktura může být odlišná.

Přístup 2: Use # as hlídka Kdekoli levé nebo pravé dítě je null .....

Odpovězeno 23/02/2013 v 20:49
zdroj uživatelem

hlasů
0

Jak se o provedením traversal na zakázku a uvedení kořenový klíč a všech uzlů klíče do objektu typu std :: seznamu nebo jiné nádoby podle svého výběru, který zplošťuje strom. Poté jednoduše serializovat std :: seznam nebo kontejneru podle svého výběru pomocí knihovny boost.

Opak je jednoduchý a znovu sestavit stromu za použití standardního vložení do binárního stromu. To nemusí být zcela efektivní pro velmi velký strom, ale běhu převést strom na std :: seznamu je O (n), nanejvýš a znovu sestavit stromu je O (log n), nanejvýš.

Chystám se to udělat, aby serializaci strom Jen jsem kódovaný v C ++ jako já konverzi svou databázi z Javy do C ++.

Odpovězeno 12/03/2013 v 18:59
zdroj uživatelem

hlasů
12

Všechny tyto články hovořit hlavně o serializace části. Deserializace část je mírně ošidné dělat v jednom průchodu.

Jsem implementoval efektivní řešení pro deserializace taky.

Problém: Serializovat a rekonstruovat binární strom obsahující kladná čísla.

Serializace část:

  1. Použijte 0 reprezentovat null.
  2. Serializovat do seznamu celých čísel s využitím předobjednání traversal.

Deserializace část:

  1. Bere v seznamu čísel a využívá rekurzivní pomocnou metodu pro deserializace.
  2. Rekurzivní deserializer vrací dvojici (BTNode uzel, Int nextIndexToRead), ve kterém uzel je uzel stromu konstruovány tak daleko, a nextIndexToRead je poloha další číslo třeba číst v serializované seznamu čísel.

Níže je uveden kód v jazyce 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;
    }
}
Odpovězeno 24/08/2013 v 21:28
zdroj uživatelem

hlasů
0

Nejlepší způsob, jak je použít speciální znak (například # jako předchozí komentář výše) jako strážce. Je to lepší než vybudování nezbytného traversal pole a pole traversal preorder / postorder, a to jak v prostorové složitosti moudrý a časové složitosti moudrý. je to také způsob, jak snadněji realizovat.

Propojený seznam není dobrou volbou, protože zde, aby se rekonstruovat strom, je lepší mít přístupovou dobu const prvek

Odpovězeno 19/03/2014 v 23:07
zdroj uživatelem

hlasů
2

Použitím předem objednat traversal, serializaci binární strom. Použijte stejný předem objednat traversal rekonstruovat strom. Dávejte pozor na případy hran. Zde jsou null uzly reprezentovány „#“

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;
    } 
Odpovězeno 18/01/2016 v 17:56
zdroj uživatelem

hlasů
0

Snažil jsem se dostat podstatu toho. Takže tady je moje implementace Java. Jak již bylo uvedeno, jedná se o binární strom není BST. Pro serializaci, zdá preorder traversal, že pracuje snadněji (na řetězec „NULL“ pro nulové uzly). Zkontrolujte prosím níže uvedený kód kompletní příklad rekurze volání. Pro deserializing, řetězec je převeden na lineární seznam kde odebrat (0) dostane horní topné těleso v O (1) čas běží. Viz také kompletní příklad v komentářích kodexu pro deserializing. Doufají, že pomůže někdo snaží méně než já :) Celková doba chodu pro každou metodu (serializaci a rekonstruovat) je stejná doba chodu pro binární strom průchod, tedy O (n), kde n je počet uzlů (záznamů) ve stromě

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


}

}

Odpovězeno 21/12/2017 v 16:43
zdroj uživatelem

hlasů
-1

Tady je další způsob, jak serializovat binárního stromu pomocí objednávkového Traversal (upravený) úrovně. [Jen kopírovat pasty, to funguje] Zahrnují všechny nevyvážené, vyvážený, správná asymetrické, levý zkosený strom.

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
Odpovězeno 28/11/2018 v 00:14
zdroj uživatelem

hlasů
0

Zde je pozdní odpověď v Pythonu. Využívá (hloubka první) předobjednávku serializace a vrátí seznam strings. Deserializace vrací strom.

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

Testovat:

tree1 = Node('root', Node('left'), Node('right'))
t = deserialize(serialize(tree1))
print(str(t.right.val))
Odpovězeno 28/02/2019 v 02:19
zdroj uživatelem

hlasů
-1

Serializace je proces konverzi datové struktury nebo objekt do posloupnosti bitů tak, že mohou být uloženy v souboru nebo vyrovnávací paměti, nebo přenášena přes spojení síťové připojení k rekonstrukci později ve stejném nebo jiném počítačovém prostředí.

Deserializace je proces převodu řetězec zpět do původní stromové struktury.

Koncept serializace a deserializace je velmi podobný tomu, co dělá kompilátor kódovat. Existuje několik fází v celém procesu kompilace, ale budeme se snažit, aby to abstraktní.

Vzhledem k tomu, část kódu, překladač rozbije různé dobře definované složky do žetony (například int je token, dvojitý je další známka, {je token,} je další známka, atd). [Odkaz na demonstraci na abstraktní úrovni sestavení] [1].

Serializace: Používáme předobjednávku traversal logiku pro serializaci stromu na řetězec. Přidáme „X“ k označení prázdného ukazatele / uzel stromu. Kromě toho, aby naše deserializace logiku na paměti, musíme přidat „“ po každé serializovaném hodnotě uzlu, takže proces deserializace může přistupovat každý uzel hodnoty rozkol s „“.

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

Vysvětlení by zády k sobě SWE YouTube kanál : 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));
Odpovězeno 16/07/2019 v 22:52
zdroj uživatelem

hlasů
0

Nejsem pomocí předobjednávku, ale já používám BFS. To je otázka, z leetcode

Většina lidí realizace jsou nesprávné při použití předběžnou objednávku: očekávaný výsledek by měl být

"[1,2,3, null, null, 4,5]", ale většina lidí vytisknout výstup jako "[1,2,3, null, null, 4,5, null, null]", protože jsou nepočítáme-li úrovně.

Tady je moje implementace se správným výsledkem.

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)
Odpovězeno 09/10/2019 v 02:02
zdroj uživatelem

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