字典特里太大了

时间:2013-06-11 00:57:49

标签: c# dictionary trie

我为字典查找类构建了一个trie。它似乎工作得很好,除了trie非常大。似乎是大约80 MB,从我读过它应该只有5 MB大。我不知道是什么让trie气球达到80 MB,一旦它加载它运行速度令人难以置信。

Trie Class

public class Trie {


private TrieNode root = new TrieNode();
public const int ASCIIA = 97;

public TrieNode Insert(string word) {

    char[] charArray = word.ToLower().ToCharArray();
    TrieNode node = root;

    foreach (char character in charArray) {
        node = Insert(character, node);

    }

    node.IsEnd = true;
    return root;
}

private TrieNode Insert(char character, TrieNode node) {
    if (node.Contains(character)) {
        return node.GetChild(character);
    } else {
        int number = System.Convert.ToByte(character) - TrieNode.ASCIIA;
        TrieNode treeNode = new TrieNode();
        node.nodes[number] = treeNode;
        treeNode.Value = number;
        return treeNode;
    }

}

TrieNode类:

public class TrieNode {

public TrieNode[] nodes;
public bool IsEnd {get; set;}
public int Value {get; set;}
public const int ASCIIA = 97;
public const int ENGL = 26;

public TrieNode() {
    nodes = new TrieNode[ENGL]; 
}

public bool Contains(char character) {
    if (character == 0) 
        return false;

    int number = System.Convert.ToByte(character) - ASCIIA;

    if (number > ENGL)
        return false;

    return (nodes[number] != null);
}


public bool Contains(int character) {

    if (character == 0) 
        return false;

    return (nodes[character] != null);
}

public TrieNode GetChild(char character) {
    int number = System.Convert.ToByte(character) - ASCIIA;
    return nodes[number];
}

public TrieNode GetChild(int character) {
    return nodes[character];
}

然后使用一本170,000字的字典来传递给特里,

    string[] lines = fileTXT.Split("\n"[0]);
for (int i = 0; i < data.Length;i++) {
        trieDict.Insert(data[i]);
}

3 个答案:

答案 0 :(得分:2)

  1. 问题是您使用的是26个项目的子节点数组。他们中的大多数都是空的。平均而言,基于32位或64位计算机,每个节点将需要26 * 4或26 * 8字节。
  2. 您正在构造函数中初始化Child节点,这意味着,即使您的节点是叶节点,您仍然分配26 * BYTES,这是完全没用的。如果需要存储子项,则只分配数组。 TRIE中的叶节点不需要子数组。
  3. 为了进一步减小尺寸,您可以简单地使用位智能Trie,它只需要两个节点,但是,它会增加计算时间并以非常小的因素降低性能。 CPU使用bitically trie来识别要执行的机器指令。
  4. 您可以使用Dictionary而不是数组,它不会分配所有26个字母,如本答案How to create a trie in c#中所述。而且你也可以减少默认容量。

答案 1 :(得分:0)

你可以做的一件事是将TrieNode变成一个结构,然后避免在初始化后修改它...但是你可能还想做一次内存转储并检查内存,因为它可能没有占用你所需的空间think ...任务管理器中为进程报告的内存不是应用程序使用的内存 ,而是.NET运行时的应用程序内存保留。 / p>

答案 2 :(得分:0)

从大字典创建trie时,我遇到了同样的问题。所以我用这些单词构造了一个DAWG(有向无环字图),它占用了很小的空间(甚至比我的单词字典还要少),保留了与trie相同的性能,甚至可能更快。它的工作原理是识别单词中的常见后缀和前缀,并从中创建有限的自动机。如果您的字典是静态的,您可以创建DAWG并将其保存到磁盘,您可以在应用程序中轻松加载它(它使用整数数组实现)。 Here是一种实施方式。