[英]Serialize and Deserialize Trie-like Data Structure
我正在嘗試序列化和反序列化類似Trie的數據結構,該結構在每個節點中都有數據/字符。 因此,要形成一個完整的詞,需要從根到葉節點遍歷。
序列化和反序列化應按順序遍歷,即以DFS方法處理子級。
#
標記該節點的遍歷結束,即類似trie的節點不再有子節點。
這是我嘗試過的。
public class SerializeDeserialize {
public static void main(String[] args) {
// prepare TrieNode Tree
TrieNodeSD root = buildTrienodeTree();
StringBuilder sb = new StringBuilder();
serialize(root, sb);
sb.deleteCharAt(sb.length()-1);
System.out.println(sb.toString());
System.out.println();
TrieNodeSD newRoot = deserialize(sb.toString().split(","), new int[] {0});
StringBuilder newsb = new StringBuilder();
serialize(newRoot, newsb);
newsb.deleteCharAt(newsb.length()-1);
System.out.println(newsb.toString());
}
private static void serialize(TrieNodeSD node, StringBuilder sb) {
if (node == null) return;
sb.append(node.character + ",");
if (node.characters != null && node.characters.size() > 0) {
for (Character c : node.characters.keySet()) {
serialize(node.characters.get(c), sb);
}
}
sb.append("#,");
}
// DOESN'T WORK!!
private static TrieNodeSD deserialize(String[] data, int[] t) {
if (t[0] >= (data.length-1) || data[t[0]].equals("#")) return null;
TrieNodeSD node = new TrieNodeSD(data[t[0]].charAt(0));
t[0] = t[0] + 1;
TrieNodeSD child = deserialize(data, t);
if (child != null) node.characters.put(child.character, child);
return node;
}
private static TrieNodeSD buildTrienodeTree() {
TrieNodeSD root = new TrieNodeSD('A');
root.characters.put('B', new TrieNodeSD('B'));
root.characters.get('B').characters.put('E', new TrieNodeSD('E'));
root.characters.get('B').characters.put('F', new TrieNodeSD('F'));
root.characters.get('B').characters.get('F').characters.put('K', new TrieNodeSD('K'));
root.characters.put('C', new TrieNodeSD('C'));
root.characters.put('D', new TrieNodeSD('D'));
root.characters.get('D').characters.put('G', new TrieNodeSD('G'));
root.characters.get('D').characters.put('H', new TrieNodeSD('H'));
root.characters.get('D').characters.put('I', new TrieNodeSD('I'));
root.characters.get('D').characters.put('J', new TrieNodeSD('J'));
return root;
}
}
class TrieNodeSD {
Map<Character, TrieNodeSD> characters;
char character;
public TrieNodeSD(char c) {
this.characters = new HashMap<Character, TrieNodeSD>();
this.character = c;
}
@Override
public String toString() { return this.character + ""; }
}
序列化會以預定格式(例如A,B,E,#,F,K,#,#,#,C,#,D,G,#,H,#,I,#,J,#,#,#
)。
PROBLEM:
反序列化期間,代碼無法正確處理所有子項,也無法將它們與正確的父項關聯。
有人可以建議如何解決deserialize
方法中的處理問題,或者可以幫助我獲得指針嗎?
不太確定trie data structure
,但是如果您引用的是trie
那么一定會有一些誤解。
...與二叉搜索樹不同,樹中沒有節點存儲與該節點關聯的關鍵字 ; 相反,它在樹中的位置定義了與其關聯的鍵。 節點的所有后代都有一個與該節點關聯的字符串的公共前綴 ,而根與空字符串關聯...
(來自Wiki的內容,我只是添加了重點)
問題:反序列化期間,代碼無法正確處理所有子項,也無法將它們與正確的父項關聯。
即使對於在節點中具有鍵的樹形結構,您的解決方案仍然無法使用,因為您通過使用map
而不是fixed-sized
數組來忽略子級的大小 ,這對於反序列化序列化數據非常重要。
使用map
使得無法確定哪個節點是父節點,哪些節點是子節點。
至於binary search tree
或真正的trie tree
,它們的結構是預定義的,由於它們是確定性的,因此您可以通過它們對樹進行序列化和反 序列化 。
也許樹根是您真正想要的。
順便說一句,您實際上可以直接在*Node
序列化和反 序列化 。
例如序列化可以是這樣的:
@Override
public String toString() {
List<String> resultList = new ArrayList<>();
for (TrieNode child : children) {
if (child == null) resultList.add("#");
else resultList.add(child.toString());
}
return resultList.stream().collect(Collectors.joining(","));
}
最終找到了反序列化Trie-Like數據結構的預序列化形式的方法。
import java.util.HashMap;
import java.util.Map;
/**
* A<br>
* / | \<br>
* B C D<br>
* / \ / / \ \<br>
* E F G H I J<br>
* |<br>
* K<br>
*
*
*/
public class SerializeDeserialize {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
StringBuilder newsb = new StringBuilder();
// prepare TrieNode Tree
TrieNodeSD root = buildTrienodeTree();
// serialize tree into string
serialize(root, sb);
sb.deleteCharAt(sb.length() - 1);
System.out.println(sb.toString());
System.out.println();
// construct tree again from serialized string
TrieNodeSD newRoot = deserialize(sb.toString().split(","), new int[] { 0 });
// Verify : again serialize above de-serialized tree to match both
// trees serialized format.
serialize(newRoot, newsb);
newsb.deleteCharAt(newsb.length() - 1);
System.out.println(newsb.toString());
}
private static void serialize(TrieNodeSD node, StringBuilder sb) {
if (node == null) return;
sb.append(node.character + ",");
if (node.characters != null && node.characters.size() > 0) {
for (Character c : node.characters.keySet()) {
serialize(node.characters.get(c), sb);
}
}
sb.append("#,");
}
private static TrieNodeSD deserialize(String[] data, int[] t) {
if (t[0] >= (data.length - 1) || data[t[0]].equals("#")) return null;
TrieNodeSD node = new TrieNodeSD(data[t[0]].charAt(0));
while (true) {
t[0] = t[0] + 1;
TrieNodeSD child = deserialize(data, t);
if (child != null) node.characters.put(child.character, child);
else break;
}
return node;
}
private static TrieNodeSD buildTrienodeTree() {
TrieNodeSD root = new TrieNodeSD('A');
root.characters.put('B', new TrieNodeSD('B'));
root.characters.get('B').characters.put('E', new TrieNodeSD('E'));
root.characters.get('B').characters.put('F', new TrieNodeSD('F'));
root.characters.get('B').characters.get('F').characters.put('K', new TrieNodeSD('K'));
root.characters.put('C', new TrieNodeSD('C'));
root.characters.put('D', new TrieNodeSD('D'));
root.characters.get('D').characters.put('G', new TrieNodeSD('G'));
root.characters.get('D').characters.put('H', new TrieNodeSD('H'));
root.characters.get('D').characters.put('I', new TrieNodeSD('I'));
root.characters.get('D').characters.put('J', new TrieNodeSD('J'));
return root;
}
}
class TrieNodeSD {
Map<Character, TrieNodeSD> characters;
char character;
public TrieNodeSD(char c) {
this.characters = new HashMap<Character, TrieNodeSD>();
this.character = c;
}
@Override
public String toString() {
return this.character + "";
}
}
樣本運行:以預遍歷序列化給定的Trie-Like數據結構,使用序列化的字符串構造類似於數據結構的Trie-data,即反序列化並最終再次序列化以驗證序列化的形式與實際樹匹配。
A,B,E,#,F,K,#,#,#,C,#,D,G,#,H,#,I,#,J,#,#,#
A,B,E,#,F,K,#,#,#,C,#,D,G,#,H,#,I,#,J,#,#,#
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.