我正在尝试构造一个后缀trie,并且由于严格的要求,它必须在内存中编入索引。
编辑:问题不在于树本身,而在于我阅读文件的方式。答案 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
此时你的特里表现得更有效率。您将决定如何处理终端节点表示,以确保查找准确。