C#内存不足异常

时间:2012-03-12 17:58:56

标签: memory memory-management memory-leaks

我正在尝试构造一个后缀trie,并且由于严格的要求,它必须在内存中编入索引。

编辑:问题不在于树本身,而在于我阅读文件的方式。

1 个答案:

答案 0 :(得分:2)

如果您将整个文本文件作为单个string传递,则可能很容易在第一次循环时遇到内存不足异常!

// imagine if s.Length was 100k or so
for (int i = 0; i < s.Length; i++)
{
    AddString(s.Substring(i, s.Length-i));
}

在阅读文件以构建trie时,您需要拆分每一行并可能规范化字符:

string line;
while (null != (line = reader.ReadLine()))
{
    string[] parts = line.Split(' ', ',', '.', '!', '\t', '?'); // naive
    foreach (string part in parts)
    {
        if (part.Length > 0)
        {
            // make each string uppercase so as to avoid Hello and hello being
            // two trie entries
            trie.AddSuffix(part.ToUpperInvariant());
        }
    }
}

例如(在dir /b c:\windows的输出上):

A
 D
  D
   I
    N
     S
  E
   D
 P
  P
   C
    O
     M
      P
       A
        T
   P
    A
     T
      C
       H
...

为了适当地处理更大的文件,需要更紧凑的trie结构。我只是将非共享后缀存储在单独的字典中:

// If you add a character, but there is no entry in m_children
// just park the tail end of it here
Dictionary<char, string> m_tails;

然后,您可以将每个字符逻辑移动到AddString的{​​{1}}:

SuffixNode

现在你有一个更紧凑的trie版本,这将大大减少为任何给定语料库创建的子public void AddString(string s) { if (s.Length == 0) return; char c = s[0]; if (m_children.ContainsKey(c)) { if (s.Length > 1) m_children[c].AddString(s.Substring(1)); } else if (m_tails.ContainsKey(c)) { SuffixNode node = new SuffixNode(); node.AddString(m_tails[c]); if (s.Length > 1) node.AddString(s.Substring(1)); m_children.Add(c, node); m_tails.Remove(c); } else { m_tails.Add(c, s.Length > 1 ? s.Substring(1) : ""); } } 的数量。回到SuffixNode示例,我们可以看到节点的实际减少:

dir /b c:\windows

此时你的特里表现得更有效率。您将决定如何处理终端节点表示,以确保查找准确。