2012-03-12 45 views
1

我试图构造一个后缀trie,并且由于严格的要求,它必须在内存中编入索引。C#中的内存不足异常#

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

+0

我的猜测是该文件太大,你没有足够的内存。增加最大堆大小并再次运行。 – duffymo 2012-03-12 18:01:46

+0

请参阅http://stackoverflow.com/questions/9649722/how-to-refer-to-children-in-a-tree-with-millions-of-nodes和http://stackoverflow.com/questions/9670080/memory-exception-in-c-sharp – Yahia 2012-03-12 18:02:36

+1

有多大?你如何索引文件? – 2012-03-12 18:09:36

回答

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

当读取文件,构建线索,你需要拆分每一行,并可能正常化的人物:(从dir /b c:\windows的输出)

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()); 
     } 
    } 
} 

例如:

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

为了适当地处理较大的文件,需要更紧凑的特里结构。我只想有存储在一个单独的字典非共享后缀:

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

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

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

此时您的线索有更高效的表现。您需要确定如何处理终端节点表示,以确保查找的准确性。

+0

感谢您的建议 - 我尝试实施您的建议,但实际只读取了一小段文本文件。任何想法为什么? – Palindrome 2012-03-12 18:09:54

+0

我得到了trie中可用的所有文件,并能够使用您的代码读取相当大的文件。但是我尚未确定限制。 – user7116 2012-03-12 18:16:08

+0

有一件事你应该注意的是,当你使用'Dictionary'的时候,在代码行方面是有效的,但是当你进入一个大的语料库时,在内存表示方面可能效率很低。 – user7116 2012-03-12 18:21:00