我在后面一个 线索 的概念。但我得到一个有点糊涂,当谈到实施。
I get the concept behind a trie. But I get a little confused when it comes to implementation.
最简单的方法我能想到构造一个特里
类型将有一个特里
维持内部词典<焦炭,特里>
。其实我已写了一个这样一来,它的和的,但是......这似乎有点小题大做。我的IM pression是一个线索应该是轻量级的,并具有独立的词典<焦炭,特里>
的的每一个节点的似乎并不非常轻巧我。
The most obvious way I could think to structure a Trie
type would be to have a Trie
maintain an internal Dictionary<char, Trie>
. I have in fact written one this way, and it works, but... this seems like overkill. My impression is that a trie should be lightweight, and having a separate Dictionary<char, Trie>
for every node does not seem very lightweight to me.
有没有实现这个结构我就是缺少一个更合适的方式?
Is there a more appropriate way to implement this structure that I'm missing?
更新:OK!根据来自Jon和leppie非常有帮助的投入,这是我想出来的,到目前为止:
UPDATE: OK! Based on the very helpful input from Jon and leppie, this is what I've come up with so far:
(1)我有特里
类型,它有一个类型的私人 _nodes
成员 Trie.INodeCollection
。
(1) I have the Trie
type, which has a private _nodes
member of type Trie.INodeCollection
.
(2) Trie.INodeCollection
接口有如下成员组成:
(2) The Trie.INodeCollection
interface has the following members:
interface INodeCollection
{
bool TryGetNode(char key, out Trie node);
INodeCollection Add(char key, Trie node);
IEnumerable<Trie> GetNodes();
}
(3)有此接口的三种实现:
(3) There are three implementations of this interface:
class SingleNode : INodeCollection
{
internal readonly char _key;
internal readonly Trie _trie;
public SingleNode(char key, Trie trie)
{ /*...*/ }
// Add returns a SmallNodeCollection.
}
class SmallNodeCollection : INodeCollection
{
const int MaximumSize = 8; // ?
internal readonly List<KeyValuePair<char, Trie>> _nodes;
public SmallNodeCollection(SingleNode node, char key, Trie trie)
{ /*...*/ }
// Add adds to the list and returns the current instance until MaximumSize,
// after which point it returns a LargeNodeCollection.
}
class LargeNodeCollection : INodeCollection
{
private readonly Dictionary<char, Trie> _nodes;
public LargeNodeCollection(SmallNodeCollection nodes, char key, Trie trie)
{ /*...*/ }
// Add adds to the dictionary and returns the current instance.
}
(4)当第一次构建了一个特里
,它的 _nodes
成员空
。以第一个调用添加
创建一个 SingleNode
,并在随后对添加
从那里,根据上述的步骤
(4) When a Trie
is first constructed, its _nodes
member is null
. The first call to Add
creates a SingleNode
, and subsequent calls to Add
go from there, according to the steps described above.
这是否有道理?这感觉就像在这个意义上的改进,它的有点的降低的特里
(节点都不再完全成熟词典&LT;焦炭,特里&GT; 对象,直到有了孩子足够数量的)。然而,这也成为显著更加复杂。是不是太令人费解?我是否采取了复杂的路线来实现的东西,应该已经直截了当?
Does this make sense? This feels like an improvement in the sense that it somewhat reduces the "bulkiness" of a Trie
(nodes are no longer full-blown Dictionary<char, Trie>
objects until they have a sufficient number of children). However, it has also become significantly more complex. Is it too convoluted? Have I taken a complicated route to achieve something that should've been straightforward?
那么,你需要每个节点有一些东西,的有效的工具的IDictionary&LT;焦炭,特里&GT;
。你可以写自己的自定义实现,它改变其内部结构的基础上有多少子节点有:
Well, you need each node to have something which effectively implements IDictionary<char, Trie>
. You could write your own custom implementation which varies its internal structure based on how many subnodes it has:
字符
和特里
对于一个小数目,使用名单,其中元组LT;焦炭,特里&GT;&GT;
或的LinkedList&LT;元组LT;焦炭,特里&GT;&GT ;
对于数量众多,使用词典&LT;焦炭,特里&GT;
For a single subnode, use just a char
and a Trie
For a small number, use a List<Tuple<char, Trie>>
or a LinkedList<Tuple<char,Trie>>
For a large number, use a Dictionary<char, Trie>
(刚刚看到leppie的答案,这是他谈,我相信那种混合的方法。)
(Having just seen leppie's answer, this is the kind of hybrid approach he talks about, I believe.)