Ik ging naar een interview vandaag, waar ik werd gevraagd om een binaire boom serialize. I uitgevoerd een array-gebaseerde benadering waarbij de kinderen van knooppunt i (nummering niveauverschillen orde traversal) werden bij 2 * i index voor de linkerkind 2 * i + 1 van de rechterkind. De interviewer leek min of meer tevreden, maar ik vraag me af wat serialize betekent dat precies? Is het in het bijzonder betrekking hebben op de boom afvlakking voor het schrijven naar de schijf, of zou een boom omvatten ook gewoon draaien van de boom in een gekoppelde lijst serialisatiepakket, zeg. Ook, hoe zouden we gaan over de boom afvlakking in een (dubbel) gelinkte lijst, en vervolgens te reconstrueren? Kun je opnieuw de precieze structuur van de boom uit de gekoppelde lijst?
Hoe te Serialize Binary Tree
bron van user worker1138
In andere talen...
Benadering 1: Hebben beide Inorder en voorbestellen traversal om de boom data searialize. Op de-serialisatie gebruik Pre-order en doen BST op Inorder om de boom op de juiste vormen.
Je moet zowel omdat A -> B -> C kan worden voorgesteld als pre-order, hoewel de structuur anders kan zijn.
Benadering 2: Gebruik # als een schildwacht whereever links of naar rechts kind null .....
Hoe zit het met het uitvoeren van een in-orde traversal en de invoering van de root key en al knooppunt sleutels in een std :: lijst of een andere container van uw keuze, die de boom afvlakt. Dan gewoon serialize de std :: list of container van uw keuze met behulp van de boost bibliotheek.
Het omgekeerde is eenvoudig en de boom bouwen met behulp van standaard insertie van een binaire boom. Dit is misschien niet helemaal efficiënt voor een zeer grote boom, maar runtime zijn om de boom te zetten in een std :: list is O (n) bij de meeste en de boom weer op te bouwen is O (log n) bij de meeste.
Ik sta op het punt om dit te doen aan een boom ik gewoon gecodeerd in c ++ als ik mijn gegevensbestand omzetten van Java naar C ++ serialize.
Al die artikelen te praten vooral over de serialisatie deel. De deserialisatie deel enigszins lastig te doen in een keer.
Ik heb een efficiënte oplossing voor deserialisatie ook geïmplementeerd.
Probleem: Serialize en deserialiseren een binaire boom met positieve getallen.
Serialization deel:
- Gebruik 0 tot nul te vertegenwoordigen.
- Serialize naar de lijst van gehele getallen met behulp van preorder traversal.
Deserialisatie deel:
- Neemt in de lijst van gehele getallen en maakt gebruik van recursieve helper methode voor deserialisatie.
- Recursieve deserializer geeft een paar (BTNode knooppunt int nextIndexToRead) wanneer knooppunt boomknooppunt dusver geconstrueerd en is nextIndexToRead positie volgend nummer te lezen in de geserialiseerde lijst met nummers.
Hieronder vindt u de 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;
}
}
De beste manier is om een speciale char te gebruiken (zoals # als eerdere opmerking genoemd) als sentinel. Het is beter dan de bouw van een inorder traversal array en een preorder / postorder traversal array, zowel in de ruimte complexiteit wijs en tijd complexiteit wijs. Het is ook veel gemakkelijker te implementeren.
Gelinkte lijst is niet een goede pasvorm hier al sinds om de boom te reconstrueren, kun je beter const element toegangstijd
Met behulp van pre order traversal, serialize Binary boom. Gebruik dezelfde pre order traversal tot boom deserialize. Wees voorzichtig over de rand gevallen. Hier null knooppunten worden voorgesteld door "#"
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;
}
Ik heb geprobeerd om de kern van het te krijgen. Dus hier is mijn Java-implementatie. Zoals gezegd, dit is een binaire boom geen BST. Voor serialiseren, een preorder traversal lijkt gemakkelijker te werken (om een string met "NULL" voor null nodes). Controleer de onderstaande code met een compleet voorbeeld van recursie gesprekken. Voor deserialize, wordt de tekenreeks omgezet in een LinkedList waarbij remove (0) wordt het topelement in een O (1) looptijd. Zie ook een volledig voorbeeld in de opmerkingen van de code voor deserialize. Hoop dat zal helpen iemand die moeite hebben minder dan ik had :) De totale looptijd voor elke methode (serialiseren en deserialize) is dezelfde looptijd voor binaire boom traversal, dat wil zeggen, O (n) waarbij n het aantal knooppunten (entries) in de boom
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();
}
}
Hier is een andere manier van serialisatiepakket binaire boom met behulp van (gewijzigd) niveau orde traversal. [Kopieer plakken, het werkt] Omvat alle ongebalanceerd, evenwichtig, rechts scheef, links scheve boom.
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
Hier is een late antwoord in Python. Het maakt gebruik van (diepte eerste) preorder rangschikking en geeft een lijst van strings. Deserialisatie geeft de boom.
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
Testen:
tree1 = Node('root', Node('left'), Node('right'))
t = deserialize(serialize(tree1))
print(str(t.right.val))
Serialisatie is het proces waarbij een datastructuur of voorwerpen in een reeks bits, zodat het kan worden opgeslagen in een bestand of geheugenbuffer of verzonden via een netwerkverbinding link later gereconstrueerd in dezelfde of een andere computeromgeving.
Deserialisatie is het proces waarbij de string terug naar de oorspronkelijke boomstructuur.
Concept van serialisatie en deserialisatie is zeer vergelijkbaar met wat een compiler doet om code. Er zijn meerdere fasen in het gehele compilatie proces, maar we zullen proberen om het abstract te houden.
Gegeven een stukje code compiler breekt verschillende goed gedefinieerde componenten in tokens (bijvoorbeeld int een token, doublet een token, {is een token,} is een token, etc). [Link naar een demonstratie van de abstracte niveau van de compilatie] [1].
Serialization: Wij gebruiken preorder traversal logica voor de serialisatie boom naar een string. We zullen "X" toevoegen aan een null pointer / knooppunt in een boom aan te duiden. Bovendien, om onze deserialisatie logica in gedachten te houden, moeten we toe te voegen "" na elke series nodewaarde zodat de deserialisatie proces hebt toegang tot elk knooppunt waarde split met "".
Leetcode link: https://leetcode.com/problems/serialize-and-deserialize-binary-tree/
Uitleg door Back To SWE Youtube kanaal Back : 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));
Ik ben niet met behulp van pre-order, maar ik ben met behulp van BFS. Dit is een vraag van leetcode
Meerderheid van de mensen implementatie onjuist zijn bij het gebruik van pre-order: het verwachte resultaat zou moeten zijn
"[1,2,3, null, 4,5]", maar meeste mensen print de uitgang als "[1,2,3, null, 4,5, null]" aangezien zij nog afgezien van de levels.
Hier is mijn implementatie met de juiste resultaat.
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)