Javascript 字典的链表与数组

Javascript 字典的链表与数组,javascript,algorithm,dictionary,data-structures,analysis,Javascript,Algorithm,Dictionary,Data Structures,Analysis,最近在一次采访中,我被问及用于单词词典实现的链表和数组的优缺点,以及实现它的最佳数据结构是什么?我把事情搞砸了。在谷歌搜索之后,我并没有找到字典特有的确切答案,只是找到了一般的链表解释以上问题的最佳答案是什么?没有一个答案 两个明显的选择是,如果您只想查找单个项目,则基于哈希表;如果您想查找项目范围,则基于平衡树 如果您进行大量搜索,而插入或删除相对较少,则排序数组可以很好地工作。找到首选链表的情况相当困难。根据具体情况(特别是查找所有以“ste”开头的单词),尝试也可以非常有效(并且通常在最小

最近在一次采访中,我被问及
用于单词词典实现的链表和数组的优缺点
,以及
实现它的最佳数据结构是什么?
我把事情搞砸了。在谷歌搜索之后,我并没有找到字典特有的确切答案,只是找到了一般的链表解释以上问题的最佳答案是什么?

没有一个答案

两个明显的选择是,如果您只想查找单个项目,则基于哈希表;如果您想查找项目范围,则基于平衡树

如果您进行大量搜索,而插入或删除相对较少,则排序数组可以很好地工作。找到首选链表的情况相当困难。根据具体情况(特别是查找所有以“ste”开头的单词),尝试也可以非常有效(并且通常在最小化给定数据集所需的存储方面也很有效)


不过,这些是非常广泛的类别,而不是具体的实现。还有一些变体,例如可扩展散列和分布式散列表,它们在特定情况下非常有用(也有一些类似于树的属性,因此基于范围的搜索可以相当有效)。

如果要构建字典,您希望它是一个排序结构。因此,您将使用排序数组或排序链表

  • 对于链表,检索是
    O(n)
    ,因为您必须检查所有单词,直到找到所需的单词。对于排序数组,可以使用二进制搜索来找到正确的位置,即
    O(logn)
  • 对于排序数组,insert
    O(logn)
    来找到正确的位置(二进制搜索),然后
    O(n)
    来插入,因为您需要向下推所有内容。对于链表,查找位置需要
    O(n)
    ,然后插入
    O(1)
    ,因为您只需调整指针。这同样适用于删除
因为您不需要经常更新字典,所以可以在
O(nlog n)
time(例如使用快速排序)中构建并排序数组。之后,使用二进制搜索进行查找。此外,正如delnan在下面提到的,使用数组的优点是,您访问的所有内容在内存中都是顺序的;i、 例如,数据是本地化的(参考位置)。这可以最大限度地减少缓存未命中(代价高昂)。使用链表时,数据会分散在各处,并且不能保证它们是紧密的,这增加了缓存未命中的可能性。记住这一点,如果有两个选项,请使用数组

如果使用红黑树实现排序的hashmap,您可以做得更好(您的树条目,即键可以与hashmap耦合);这里的搜索、插入和删除是
O(log n)
。但这确实取决于你的行为模式;如果您只进行查找,那么一个简单的hashmap将是最好的(
O(1)
retrieval)


您可以使用的另一个有趣的数据结构是a,其中插入和查找是
O(m)
m
是字符串的长度

实现字典的最佳数据结构是
后缀树
。您还可以查看
尝试

如果您只是想使用它进行查找,那么数组显然是这两种方法中最好的选择。您可以从O(n log n)中的单词列表构建字典——只需构建一个数组并对其进行排序。使用二进制搜索进行O(logn)查找

虽然您可以在O(n)中构建单词的链接列表,但平均而言,查找需要查看n/2个单词。差别相当大。给定一本128K单词的英语词典,链表查找平均需要64000个字符串比较。二进制搜索最多需要17次

此外,n个单词的链接列表将比n个单词的数组占用更多内存,因为您需要列表中的
next
指针

如果您需要更新字典的功能,那么如果与查找相比更新不频繁(几乎可以肯定是这样),您可能仍然希望使用数组。我想不出一个真实世界中更新频率比查询频率更高的单词词典的例子


正如其他人指出的,数组和链表都不是单词词典的最佳选择。但在给出的两个选项中,array几乎在所有情况下都优于array。

您的这一点
对于array,插入是O(n)以找到正确的位置,然后是O(n)以插入,因为您需要向下推所有内容。对于链表来说,找到位置然后插入是O(n),因为您只需调整指针。
有点混乱
O(n)
用于链表和数组查找正确的位置和插入?两者都是O(n)?你能详细解释一下吗?@26ph19对不起,那是个打字错误!它应该是
O(1)
;编辑。我真的不明白你怎么能得出结论,链表比数组更好,至少从你介绍的事实来看。渐近复杂性是完全相同的。在找到要插入的位置后,实际的列表操作是O(1)并不重要,因为插入总体上是O(n),充其量这将是一个1/2的常数工厂,但当您开始考虑常数因子时,数组会轻而易举地获胜。@delnan我实际上对这部分有点不确定。你能解释一下恒定因素是如何获胜的吗?假设您总是在列表的中间插入一些内容,那么您将拥有
O(n/2)+O(1)
,而对于数组,它将变成
O(n)+O(n)
。恳求