序列化和反序列化 Trie-like 数据结构
Serialize and Deserialize Trie-like Data Structure
我正在尝试序列化和反序列化每个节点中具有 data/character 的 Trie-like 数据结构。所以要形成一个完整的词,需要从根节点遍历到叶节点。
序列化和De-serialization应该在pre-order遍历中,即在DFS方法中处理children。
#
标记该节点的遍历结束,即 trie-like 节点不再有 children.
这是我试过的。
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 + ""; }
}
序列化以 pre-order 格式输出(例如 A,B,E,#,F,K,#,#,#,C,#,D,G,#,H,#,I,#,J,#,#,#
)。
PROBLEM:
在 de-serialization 期间,代码没有正确处理所有 children,也没有将它们与正确的 parent.
相关联
有人可以建议如何修复 deserialize
方法中的处理或帮助我指点我错过了什么吗?
不太清楚你的trie data structure
,但如果你指的是trie
,那肯定是有一些误会。
trie in wiki有明确规定。
...Unlike a binary search tree, no node in the tree stores the key associated with that node; instead, its position in the tree defines the key with which it is associated. All the descendants of a node have a common prefix of the string associated with that node, and the root is associated with the empty string...
(来自wiki的内容,我只是加了重点)
PROBLEM: during de-serialization, the code doesn't process all the children correctly and doesn't associate them with correct parent.
即使对于节点中有键的树结构,您的解决方案仍然无效,因为您忽略了 children 的 size 通过使用 map
而不是 fixed-sized
数组,这对于 反序列化 序列化数据非常重要。
使用map
无法确定哪个节点是parent,哪些节点是children。
至于binary search tree
或真正的trie tree
,它们的结构是预定义的,通过它你可以序列化和反序列化 树,因为它们是确定性的。
也许Radix 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 + "";
}
}
Sample 运行: 在前序遍历中序列化给定的Trie-Like数据结构,使用序列化后的字符串构建类似 Trie 数据的数据结构,即反序列化,最后再次序列化,以验证序列化形式与实际树匹配。
A,B,E,#,F,K,#,#,#,C,#,D,G,#,H,#,I,#,J,#,#,#
A,B,E,#,F,K,#,#,#,C,#,D,G,#,H,#,I,#,J,#,#,#
我正在尝试序列化和反序列化每个节点中具有 data/character 的 Trie-like 数据结构。所以要形成一个完整的词,需要从根节点遍历到叶节点。
序列化和De-serialization应该在pre-order遍历中,即在DFS方法中处理children。
#
标记该节点的遍历结束,即 trie-like 节点不再有 children.
这是我试过的。
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 + ""; }
}
序列化以 pre-order 格式输出(例如 A,B,E,#,F,K,#,#,#,C,#,D,G,#,H,#,I,#,J,#,#,#
)。
PROBLEM:
在 de-serialization 期间,代码没有正确处理所有 children,也没有将它们与正确的 parent.
有人可以建议如何修复 deserialize
方法中的处理或帮助我指点我错过了什么吗?
不太清楚你的trie data structure
,但如果你指的是trie
,那肯定是有一些误会。
trie in wiki有明确规定。
...Unlike a binary search tree, no node in the tree stores the key associated with that node; instead, its position in the tree defines the key with which it is associated. All the descendants of a node have a common prefix of the string associated with that node, and the root is associated with the empty string...
(来自wiki的内容,我只是加了重点)
PROBLEM: during de-serialization, the code doesn't process all the children correctly and doesn't associate them with correct parent.
即使对于节点中有键的树结构,您的解决方案仍然无效,因为您忽略了 children 的 size 通过使用 map
而不是 fixed-sized
数组,这对于 反序列化 序列化数据非常重要。
使用map
无法确定哪个节点是parent,哪些节点是children。
至于binary search tree
或真正的trie tree
,它们的结构是预定义的,通过它你可以序列化和反序列化 树,因为它们是确定性的。
也许Radix 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 + "";
}
}
Sample 运行: 在前序遍历中序列化给定的Trie-Like数据结构,使用序列化后的字符串构建类似 Trie 数据的数据结构,即反序列化,最后再次序列化,以验证序列化形式与实际树匹配。
A,B,E,#,F,K,#,#,#,C,#,D,G,#,H,#,I,#,J,#,#,#
A,B,E,#,F,K,#,#,#,C,#,D,G,#,H,#,I,#,J,#,#,#