代码之家  ›  专栏  ›  技术社区  ›  JRG

序列化和反序列化类似Trie的数据结构

  •  0
  • JRG  · 技术社区  · 7 年前

    我正在尝试序列化和反序列化一个类似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 方法或帮助我使用指针我缺少什么?

    2 回复  |  直到 7 年前
        1
  •  1
  •   JRG    7 年前

    最后找到了反序列化一种预排序序列化形式的Trie类数据结构的方法。

    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-Like数据结构,即反序列化,最后再次序列化以验证序列化的表单是否与实际树匹配。

    A,B,E,#,F,K,#,#,#,C,#,D,G,#,H,#,I,#,J,#,#,#
    
    A,B,E,#,F,K,#,#,#,C,#,D,G,#,H,#,I,#,J,#,#,#
    
        2
  •  0
  •   Hearen    7 年前

    对你的 trie data structure ,但如果你指的是 trie 那一定是有些误会。

    有一个明确的规范 trie in wiki .

    …不像二进制搜索树, 无节点 在树上存储 钥匙 与该节点关联;而是 位置 在树中定义与其关联的键。一个节点的所有子节点都有一个 公共前缀 与该节点相关联的字符串,并且根与 空的 字符串。。。

    (wiki的内容,我只是添加了重点)

    问题:在反序列化过程中,代码没有正确处理所有子级,并且没有将它们与正确的父级关联。

    即使对于节点中有键的树结构,您的解决方案仍然无法工作,因为您忽略了 大小 通过使用 map 而不是 fixed-sized 数组对于 反序列化 串行化的数据。

    使用 地图 使得无法确定哪个节点是父节点,哪些节点是子节点。

    至于 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(","));
    }