Poszedłem na rozmowę dzisiaj gdzie poproszono mnie do serializacji binarne drzewo. Zaimplementowałem podejście oparte na tablicach, gdzie dzieci węzła i (numerację rzędu poziom przechodzenia) były na 2 * Indeks i dla lewego dziecka oraz 2 * i + 1 do prawego dziecka. Wywiad wydawał się bardziej lub mniej zadowolony, ale zastanawiam się, co dokładnie oznacza serialize? Czy to w szczególności odnoszą się do spłaszczania drzewa do zapisu na dysku, czy też szeregowania drzewo również obejmować tylko toczenie drzewo w połączonej listy, powiedzmy. Ponadto, jak pójdziemy o spłaszczenie drzewo w (podwójnie) połączonej listy, a następnie odtworzenie go? Można odtworzyć dokładną strukturę drzewa z połączonej listy?
Jak Serializować binarne drzewo
Podejście 1: Czy zarówno Inorder i preorder przechodzenie do searialize dane drzewo. Na wykorzystanie de-serializacji pre-order i zrobić BST na Inorder właściwie tworzą drzewo.
Trzeba zarówno dlatego, A -> B -> C może być reprezentowana jako pre-order chociaż struktura może być inna.
Podejście 2: Użyj # jako wartownik gdziekolwiek dziecko lewo lub w prawo jest null .....
Jak na temat wykonywania przechodzenie na zamówienie i oddanie klucza głównego i wszystkie klucze do węzła std :: listy lub innego pojemnika do wyboru, który spłaszcza drzewo. Następnie, po prostu serializacji std :: listy lub pojemnik do wyboru przy użyciu biblioteki Boost.
Odwrotna jest proste i następnie ponownie drzewa stosując standardowe wprowadzenie do binarnego drzewa. To może nie być w pełni sprawny w bardzo dużym drzewem, ale starcie do konwersji drzewa w std :: liście jest O (n) i co najwyżej odbudować drzewa wynosi O (log n), co najwyżej.
Mam zamiar to zrobić, aby szeregować drzewa po prostu zakodowany w C ++ jak ja konwersji mojej bazy danych z Java do C ++.
Wszystkie te artykuły rozmawiać głównie o część serializacji. Część deserializacji jest nieco trudne do zrobienia w jednym przebiegu.
I wprowadziły efektywne rozwiązanie dla deserializacji też.
Problem: Serializować i deserializowania binarne drzewo zawierający liczb dodatnich.
część serializacji:
- Użyj 0 do reprezentowania null.
- Serializacji do listy liczb całkowitych z zastosowaniem preorder przechodzenie.
część Deserializacji:
- Zajmuje na liście liczb całkowitych i wykorzystuje rekurencyjną metodę pomocniczą dla deserializacji.
- Rekurencyjne Deserializator zwraca parę (węzeł BTNode, int nextIndexToRead), w którym węzeł jest węzeł drzewa skonstruowany tak daleko, a nextIndexToRead jest pozycja następnego numeru należy czytać w odcinkach listy numerów.
Poniżej znajduje się kod w Javie:
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;
}
}
Najlepszym sposobem jest użycie specjalnego char (jak # jak poprzedni komentarz wspomniano) jako strażnik. To lepsze niż konstruowaniu tablicę przejścia Inorder i przejścia tablicę preorder / postorder, zarówno w przestrzeni złożoności mądry i czasu złożoności mądry. jest to również sposób łatwiejsze do wdrożenia.
Związany lista nie jest dobrym rozwiązaniem, ponieważ tutaj w celu odtworzenia drzewa, lepiej mieć const elementu czas dostępu
Korzystanie pre order przechodzenie, szeregować drzewo binarne. Użyj tego samego pre order przechodzenie do deserializowania drzewo. Bądź ostrożny przypadków brzegowych. Tutaj zerowe węzły są reprezentowane przez „#”
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;
}
I zostały próbuje istotę tego. Więc tutaj jest mój wykonania Java. Jak już wspomniano, jest to drzewo binarne nie BST. Dla szeregowania, o przechodzenie preorder wydaje się działać łatwiej (na sznurku z „null” dla zerowych węzłów). Proszę sprawdzić poniższy kod z kompletną przykład połączeń rekursji. Na deserializacji, łańcuch jest przekształcany do LinkedList gdzie usunąć (0) osiąga górny element w O (1) Czas trwania. Proszę zobaczyć również kompletny przykład w komentarzach kodu dla deserializacji. Mam nadzieję, że ktoś pomoże walczyć mniej niż ja :) Całkowity czas jazdy dla każdej metody (serializacji i Cofnięcie) jest taki sam czas pracy na przechodzenie drzewa binarnego, czyli O (n), gdzie n jest liczbą węzłów (Wpisy) w drzewie
importu java.util.LinkedList; importu 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();
}
}
Oto kolejny sposób szeregowania drzewo binarne użyciu (zmodyfikowany) poziom zamówień przechodzenie. [Wystarczy skopiować pasty, to działa] obejmuje wszystkie niezrównoważony, zrównoważony, w prawo, w lewo skośny wypaczone drzewo.
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
Oto późno odpowiedź w Pythonie. Wykorzystuje (głębokość) pierwszy preorder serializacji i zwraca listę strings. Deserializacji zwraca drzewo.
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
Testować:
tree1 = Node('root', Node('left'), Node('right'))
t = deserialize(serialize(tree1))
print(str(t.right.val))
Szeregowanie jest procesem przekształcania struktury danych lub obiekt w sekwencji bitów tak, że może być przechowywana w buforze plików lub pamięci lub przesyłane przez łącze zasilania sieciowego zrekonstruować później w tym samym lub innym środowisku komputerowym.
Deserializacji jest proces przekształcania ciąg z powrotem do pierwotnej strukturze drzewa.
Koncepcja serializacji i deserializacji jest bardzo podobny do tego, co robi kompilator do kodu. Istnieje wiele faz w całym procesie kompilacji, ale będziemy starać się utrzymać go abstrakcyjny.
Biorąc pod uwagę to kod, kompilator przerywa różne dobrze określone podzespoły na tokeny (np int token dwukrotnie inny znacznik {jeden znacznik} inny znacznik, itp). [Link do demonstracji abstrakcyjnym poziomie kompilacji] [1].
Serializacji: Używamy preorder logikę przejścia dla szeregowania drzewo String. „Dodamy” do oznaczenia X null pointer / węzeł w drzewie. Ponadto, aby utrzymać naszą logikę deserializacjia na uwadze, musimy dodać „” po każdej wartości serializowanym węzła tak, że proces deserializacji mogą uzyskać dostęp do każdej wartości rozłamu node „”.
Link Leetcode: https://leetcode.com/problems/serialize-and-deserialize-binary-tree/
Wyjaśnienie z powrotem do tyłu przez kanał SWE 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));
Nie używam pre-order, ale używam BFS. To jest pytanie z leetcode
Większość ludzi realizacji są nieprawidłowe przy użyciu pre-order: oczekiwany wynik powinien być
"[1,2,3, null, null, 4,5]", ale większość ludzi zamiast drukować wyjście jako "[1,2,3, null, null, 4,5, null, null]", ponieważ są one nie licząc poziomów.
Oto moja realizacja z prawidłowym wynikiem.
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)













