Πήγα σε μια συνέντευξη σήμερα, όπου μου ζητήθηκε να σε συνέχειες ένα δυαδικό δέντρο. Ι υλοποιείται μια προσέγγιση που βασίζεται σε συστοιχία όπου τα παιδιά του κόμβου Ι (αρίθμηση σε διάσχιση επίπεδο-παραγγελία) βρίσκονταν στο * δείκτη 2 i για το αριστερό παιδί και 2 * i + 1 για το δικαίωμα παιδί. Ο ερευνητής έμοιαζε περισσότερο ή λιγότερο ευχαριστημένοι, αλλά αναρωτιέμαι τι σημαίνει serialize ακριβώς; Μήπως αφορούν ειδικά την ισοπέδωση το δέντρο για εγγραφή σε δίσκο, ή θα συνέχειες ένα δέντρο, επίσης, περιλαμβάνουν μόνο μετατρέποντας το δέντρο σε μια συνδεδεμένη λίστα, λένε. Επίσης, πώς θα πάει για την ισοπέδωση το δέντρο σε ένα (διπλά) συνδεδεμένη λίστα, και στη συνέχεια ανακατασκευή αυτό; Μπορείτε να αναδημιουργήσει την ακριβή δομή του δέντρου από τη συνδεδεμένη λίστα;
Πώς να Serialize Binary Tree
Προσέγγιση 1: Κάνετε τόσο Inorder και Προπαραγγελία διάσχιση να searialize τα δεδομένα δέντρο. Σχετικά με τη χρήση de-serialization Προ-παραγγελία και να κάνει BST για Inorder να σχηματίσουν σωστά το δέντρο.
Χρειάζεται τόσο επειδή A -> B -> C μπορεί να αναπαρασταθεί ως προ-παραγγελία ακόμη και αν η δομή μπορεί να είναι διαφορετική.
Προσέγγιση 2: Χρήση # ως φρουρός όπου κι το αριστερό ή το δεξί παιδί είναι άκυρη .....
Τι λέτε για την εκτέλεση μιας όδευσης σε τάξη και βάζοντας το κλειδί της ρίζας και όλα τα κλειδιά κόμβου σε ένα std :: λίστα ή άλλο δοχείο της επιλογής σας, η οποία ισοπεδώνει το δέντρο. Στη συνέχεια, απλά σε συνέχειες το std :: κατάλογο ή το δοχείο της επιλογής σας χρησιμοποιώντας τη βιβλιοθήκη ώθηση.
Το αντίστροφο είναι απλή και, στη συνέχεια, την ανοικοδόμηση του δέντρου χρησιμοποιώντας πρότυπες εισαγωγή σε ένα δυαδικό δένδρο. Αυτό δεν μπορεί να είναι απόλυτα αποτελεσματικό για ένα πολύ μεγάλο δέντρο, αλλά το χρόνο εκτέλεσης για να μετατρέψει το δέντρο σε ένα std :: κατάλογος είναι O (n) το πολύ και να ξαναχτίσουν το δέντρο είναι O (log n) το πολύ.
Είμαι έτοιμος να κάνω αυτό για να σε συνέχειες ένα δέντρο που μόλις κωδικοποιούνται σε C ++ όπως είμαι μετατροπή της βάσης δεδομένων μου από Java σε C ++.
Όλα τα άρθρα αυτά μιλούν κυρίως για το μέρος serialization. Το τμήμα deserialization είναι λίγο δύσκολο να κάνει με ένα πέρασμα.
Έχω εφαρμόσει μια αποτελεσματική λύση για deserialization πάρα πολύ.
Πρόβλημα: Serialize και αποσειριοποίηση ένα δυαδικό δέντρο που περιέχει θετικούς αριθμούς.
μέρος Serialization:
- Χρησιμοποιήστε το 0 να αντιπροσωπεύει μηδενική.
- Serialize στη λίστα των ακεραίων με τη χρήση προ-παραγγελία διάσχισης.
μέρος deserialization:
- Λαμβάνει στη λίστα των ακεραίων και χρησιμοποιεί επαναληπτική μέθοδο βοηθός για deserialization.
- Αναδρομικές deserializer επιστρέφει ένα ζεύγος (BTNode κόμβο, int nextIndexToRead) όπου ο κόμβος είναι κόμβο του δένδρου κατασκευασμένο μέχρι στιγμής, και nextIndexToRead είναι η θέση του επόμενου αριθμού για να διαβαστεί στην συνέχειες λίστα των αριθμών.
Παρακάτω είναι ο κώδικας σε 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;
}
}
Ο καλύτερος τρόπος είναι να χρησιμοποιήσετε ένα ειδικό char (όπως # ως προηγούμενο σχόλιο αναφέρεται) ως φρουρού. Είναι καλύτερο από την κατασκευή μια σειρά διάσχισης inorder και μια σειρά διάσχισης παραγγελίας / postorder, τόσο στο χώρο της πολυπλοκότητας σοφή και χρονική πολυπλοκότητα σοφός. είναι επίσης πιο εύκολο τρόπο για την εφαρμογή της.
Συνδεδεμένη λίστα δεν είναι μια καλή τακτοποίηση εδώ αφού για να ανακατασκευάσει το δέντρο, καλύτερα να έχετε το χρόνο πρόσβασης const στοιχείο
Χρησιμοποιώντας προ διάσχισης, προκειμένου, σε συνέχειες δυαδικό δέντρο. Χρησιμοποιήστε το ίδιο διάσχιση προ ώστε να αποσειριοποίηση δέντρο. Να είστε προσεκτικοί σχετικά με τις περιπτώσεις ακμής. Εδώ είναι null κόμβοι που αντιπροσωπεύεται από το «#»
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;
}
Έχω προσπαθήσει να πάρει την ουσία του. Έτσι, εδώ είναι η εφαρμογή Java μου. Όπως αναφέρθηκε, αυτό είναι ένα δυαδικό δέντρο δεν το BST. Για συνέχειες, μια διάσχιση παραγγελίας φαίνεται να λειτουργεί πιο εύκολο (σε μια σειρά με το «NULL» για μηδενική κόμβους). Παρακαλώ ελέγξτε τον παρακάτω κώδικα με ένα πλήρες παράδειγμα των κλήσεων αναδρομή. Για deserializing, η συμβολοσειρά μετατρέπεται σε ένα LinkedList όπου αφαίρεση (0) παίρνει το άνω στοιχείο σε ένα O (1) χρόνο λειτουργίας. Παρακαλώ δείτε επίσης ένα πλήρες παράδειγμα στα σχόλια του κώδικα για deserializing. Ελπίζουμε ότι θα σας βοηθήσει κάποιος αγωνίζονται λιγότερο από ό, τι έκανα :) Ο συνολικός χρόνος λειτουργίας για κάθε μέθοδο (σε συνέχειες και κατάργηση σειράς) είναι το ίδιο χρονικό διάστημα λειτουργίας για το δυαδικό διάσχιση δέντρου, δηλαδή, O (n) όπου n είναι ο αριθμός των κόμβων (καταχωρήσεις) στο δέντρο
εισαγωγής java.util.LinkedList? εισαγωγής java.util.List?
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();
}
}
Εδώ είναι ένας άλλος τρόπος συνέχειες δυαδικό δέντρο χρησιμοποιώντας διάσχιση της παραγγελίας (τροποποιημένες) επίπεδο. [Απλά αντιγράψτε πάστα, λειτουργεί] Καλύπτουν όλα τα ασύμμετρη, ισορροπημένη, δεξιά ασύμμετρη, αριστερά ασύμμετρη δέντρο.
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
Εδώ είναι μια καθυστερημένη απάντηση στην Python. Χρησιμοποιεί (βάθος πρώτα) προ-παραγγελία σειριακή και επιστρέφει μια λίστα strings. Deserialization επιστρέφει το δέντρο.
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
Να δοκιμάσω:
tree1 = Node('root', Node('left'), Node('right'))
t = deserialize(serialize(tree1))
print(str(t.right.val))
Serialization είναι η διαδικασία μετατροπής μια δομή δεδομένων ή αντικείμενο σε μια ακολουθία δυαδικών ψηφίων έτσι ώστε να μπορεί να αποθηκεύεται σε ένα ρυθμιστικό διάλυμα αρχείο ή μνήμης, ή να μεταδοθεί σε ένα σύνδεσμο σύνδεση δικτύου για να ανακατασκευαστεί αργότερα στο ίδιο ή σε άλλο περιβάλλον υπολογιστή.
Deserialization είναι η διαδικασία της μετατροπής της συμβολοσειράς πίσω στην αρχική δομή δέντρου.
Έννοια του serialization και deserialization είναι πολύ παρόμοιο με αυτό που κάνει έναν compiler για κώδικα. Υπάρχουν πολλές φάσεις στην όλη διαδικασία κατάρτισης, αλλά εμείς θα προσπαθήσουμε να το κρατήσει αφηρημένο.
Λαμβάνοντας υπόψη ένα κομμάτι του κώδικα, μεταγλωττιστή σπάει διαφορετικές καλά καθορισμένα συστατικά σε μάρκες (για παράδειγμα, int είναι μια συμβολική, διπλό είναι ένα άλλο διακριτικό, {είναι ένα κουπόνι,} είναι μια άλλη λογική, κλπ). [Σύνδεση σε μια επίδειξη του αφηρημένο επίπεδο κατάρτισης] [1].
Serialization: Χρησιμοποιούμε λογική διάσχιση παραγγελίας για συνέχειες δέντρο σε ένα String. Θα προσθέσουμε «Χ» για να υποδηλώσει ένα μηδενικό δείκτη / κόμβου σε ένα δέντρο. Επιπλέον, για να κρατήσει λογική deserialization μας κατά νου, θα πρέπει να προσθέσετε «» μετά από κάθε συνέχειες αξία κόμβο, έτσι ώστε η διαδικασία deserialization μπορεί να έχει πρόσβαση κάθε τιμή κόμβο διάσπαση με «».
Leetcode σύνδεσμο: https://leetcode.com/problems/serialize-and-deserialize-binary-tree/
Επεξήγηση με Back To Back κανάλι 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));
Δεν είμαι με τη χρήση προ-παραγγελία, αλλά είμαι με τη χρήση BFS. Αυτή είναι μια ερώτηση leetcode
Η πλειονότητα των ανθρώπων εφαρμογής είναι εσφαλμένη όταν χρησιμοποιούν προ-παραγγελία: το αναμενόμενο αποτέλεσμα θα πρέπει να είναι
"[1,2,3, null, null, 4,5]", αλλά αντ 'αυτού πλειοψηφία τους ανθρώπους να εκτυπώσετε την έξοδο ως "[1,2,3, null, null, 4,5, null, null]" δεδομένου ότι είναι χωρίς να υπολογίζονται τα επίπεδα.
Εδώ είναι η εφαρμογή μου με το σωστό αποτέλεσμα.
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)













