【问题标题】:efficient way to search for string in list of string?在字符串列表中搜索字符串的有效方法?
【发布时间】:2012-01-29 06:37:30
【问题描述】:

我有一个字符串列表,需要找出与给定输入值匹配的字符串。 我存储这个字符串列表并能够搜索它的最有效方式(内存与执行速度)是什么?字符串列表的启动和加载并不重要,但搜索的响应时间很重要。

我应该使用 List 或 HashSet 还是只使用基本字符串 [] 或其他什么?

【问题讨论】:

  • 字符串列表有多“大”?
  • 不要忘记 StringCollection 类 - msdn.microsoft.com/en-us/library/…
  • 任何字符串都可以重复吗?您需要匹配整个单词/字符串还是可以将其包含在字符串中?
  • @KrisKrause StringCollection 非常慢。它在封面下使用ArrayList
  • @Kris Krause:StringCollection 不快。

标签: c# .net memory-management


【解决方案1】:

使用Dictionary<string>()HashSet<string> 可能对你有好处。

【讨论】:

  • +1:这也是我在考虑优化字符串列表中的搜索字符串时首先想到的:第一个常见的解决方案是“索引”,字典是最常见的解决方案。
  • @StephaneRolland 是的,越简单越好,但即使是 gotafex 解决方案也值得 +1
【解决方案2】:

这在很大程度上取决于字符串的性质和集合的大小。根据集合的特征和预期的搜索字符串,有一些方法可以非常巧妙地组织事物,以便搜索非常快。你还没有向我们提供这些信息。

但这就是我要做的。我会设定一个合理的性能要求。然后我会尝试一个 n-gram 索引(为什么?因为你在评论中说你需要考虑部分匹配;HashSet<string> 在这里对你没有帮助)我会分析我期望的合理输入解决方案,看看它是否符合我的性能要求。如果是这样,我会接受解决方案并继续前进。如果没有,我会非常仔细地考虑我的性能要求是否合理。如果是,我会开始考虑我的输入和集合是否有什么特别之处,可以让我使用一些更聪明的解决方案。

【讨论】:

  • A HashSet 不能满足他对部分匹配的需求(如果字符串“可以重复”,这意味着有一些信息可以区分重复项,所以无论如何它都是字典,而不是一个哈希集)
  • @Random832:他的问题没有提到部分匹配或重复!
  • 有一个后续评论——在你急于成为 FGITW 时,你并没有停下来询问需要什么——原始措辞并不接近暗示 HashSet 可以解决的问题。仔细阅读“哪些字符串匹配给定的输入值”会发现复数意味着部分匹配(只有一个字符串可以完全匹配)
  • @Random832:冲什么?我不知道首字母缩略词是什么意思。无论如何,我并不急于任何事情。建议我仔细阅读一个甚至没有仔细编写的问题(如果稍后在评论中进行澄清以从 OP 中获取一些必要的细节)是愚蠢的。注意标题:“在字符串列表中搜索字符串的 C# 有效方法?”请注意,OP 本人询问 HashSet 是否合适。
  • 意思是“西部最快的枪”。如果问题没有提供必要的细节,那就是 cmets 的用途。 “请注意 OP 本人询问 HashSet 是否合适” - 答案是否定的。对于大多数人来说,“搜索”意味着文本搜索,例如一个文档,它通常甚至没有“仅匹配整行”的 选项,更不用说它是默认值了
【解决方案3】:

Dictionary 和 Hashtable 在“搜索”方面将是最快的,因为它的速度为 O(1)。字典和哈希表有一些缺点,因为它们没有排序。

使用二叉搜索树,您将能够进行 O(Log N) 搜索。

使用未排序的列表,您将以 O(N) 的速度进行搜索。

使用排序列表,您将获得 O(Log N) 搜索,但请记住,列表必须进行排序,以便为整体速度增加时间。

至于内存使用,请确保初始化集合的大小。

所以字典或哈希表是检索最快的。

从最好到最差的速度分类是 O(1) O(log n) 在) O(n log n) O(n^2) O(2^n)

n 是元素的数量。

【讨论】:

  • @FelicePollano 我不认为你完全有 O(1) 正确的意思。
  • @Random832 在插入时为 O(1)。在搜索中,它是 O(1) 定位列表,然后执行线性搜索。你怎么了?
  • 必须线性搜索的“列表”的事实[即碰撞链]通常很短,并且与字典中的项目总数不成比例(假设有适当数量的桶)意味着它仍然是 O(1) 摊销的,除非大量项目具有相同的哈希值代码[不太可能,除非故意以这种方式构造]。
【解决方案4】:

似乎最好的方法是在 O(input_len) 时间内为您的输入构建一个后缀树,然后在 O(pattern_length) 时间内查询您的模式。因此,如果您的文本与您的模式相比确实很大,那么这将很有效。

查看 Ukkonen 构建后缀树的算法。

如果您想要不精确的匹配...请参阅 Gonzalo Navarro 的工作。

【讨论】:

  • “只需为 trie 中的每个节点构建一个 256 或更多可能的 128 字符/字节数组。” - 数组将是 256/128 个指向节点的指针,而不是字节。
  • 或者……更准确地说……一个数组,由字符的 ascii(或其他字符集)代码索引,对象引用/指针 Node node* = new Node[128]。感谢 Random832 的改进。
  • 这是最快的吗?还是内存效率最高的?我以为是后者。
  • 鉴于需要部分匹配,前缀树并没有真正的帮助。
猜你喜欢
  • 2019-04-06
  • 2012-12-18
  • 1970-01-01
  • 2010-10-25
  • 1970-01-01
  • 2018-10-13
  • 1970-01-01
  • 2014-10-12
  • 2020-03-12
相关资源
最近更新 更多