【问题标题】:Out of Memory Exception In C# [closed]C#中的内存不足异常[关闭]
【发布时间】:2012-03-12 17:58:56
【问题描述】:

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

编辑:问题不在于树本身,而实际上是我读取文件的方式。

【问题讨论】:

标签: memory memory-management memory-leaks


【解决方案1】:

如果您将整个文本文件作为单个 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;

然后,您可以将每个字符的逻辑移动到您的 AddStringSuffixNode

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) : "");
    }
}

现在您有了一个更紧凑的 trie 版本,这将大大减少为任何给定语料库创建的子 SuffixNodes 的数量。回到dir /b c:\windows 的例子,我们可以看到节点的实际减少:

A
 P
  P
   COMPAT
   PATCH
  I
 T
  I
   O
    N
     S
...

此时,您的 trie 具有更有效的表示形式。您需要确定如何处理终端节点表示,以确保查找准确。

【讨论】:

  • 感谢您的建议 - 我尝试实施您的建议,但实际上只读取了一小部分文本文件。知道为什么吗?
  • 我得到了 trie 中可用的所有文件,并且能够使用您的代码读取相当大的文件。但是,我还没有确定限制。
  • 您应该注意的一点是,您当前对Dictionary 的使用在代码行方面是有效的,但一旦您进入大型语料库,就内存表示而言可能效率低下。跨度>
  • 我不明白发生了什么 - 我正在使用您建议的代码来读取文件,但它只读取文件的最后几句!
  • 我几乎一字不差地使用了你的代码(而不是我使用AddString(s.Substring(i)))。您是否在 while 循环中声明了 trie
猜你喜欢
  • 2012-01-23
  • 1970-01-01
  • 2016-07-27
  • 2010-09-17
  • 1970-01-01
  • 2012-07-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多