【问题标题】:What is the best data structure for a collection of words?单词集合的最佳数据结构是什么?
【发布时间】:2012-07-02 02:33:12
【问题描述】:

我收集了大约 170,000 个单词,并对它们执行了许多操作。最常见的是:StartsWithEndsWithContains。我也做了很多长度检查。

我最初将此信息存储在 List<string> 中,但后来切换到 HashSet<string>,因为我认为这种类型的数据会更快。

根据我的描述,HashSet 是该数据的最佳集合类型吗?

【问题讨论】:

  • StartsWith 并且,通过存储反向字符串或由内而外索引,EndsWith 可以从排序结构中受益,例如一棵二叉树。 Contains 并不那么容易承认性能增强,尽管长度可能是一个有用的花絮。

标签: c# .net performance collections


【解决方案1】:

trie 是一个非常好的数据结构,用于存储字符串和执行所需的文本搜索操作。是Lucene等搜索引擎中常用的索引字符串值的数据结构

通常在提到时,trie 被描述为允许非常有效的“开始于”搜索的前缀树。数据结构的suffix tree 变体在“结束于”搜索时非常有效。

可以想象,相同的 trie 实现可以用于前缀树和后缀树,只需在填充 trie 以及搜索 trie 时反转字符串。

【讨论】:

  • +1 你知道 Trie 的一些 .NET C# 示例代码吗? (对于大约 170000 字的列表)
  • @Blam 我不知道手头的实现。快速的互联网搜索应该会发现几个 C# 实现。对于大型列表,最好使用允许使用文件系统存储 trie 的列表。
  • 进行了搜索。会继续找。只是希望你有一个你喜欢的。具有讽刺意味的是,Trie 是搜索引擎喜欢使用的一个术语。
  • @Blam 对于我发现的 trie 的最佳和最易读的实现在我的回答中。利用该框架使其更简单且非常高效。
【解决方案2】:

你提到的操作都是在集合的单个元素上完成的,所以他们完全不知道你的元素实际上来自什么类型的集合。

对于集合类型要考虑的重要事项是您以何种方式处理整个集合:您是经常插入项目还是经常删除它们?您想按顺序获取每个元素,还是想更频繁地访问集合的特定部分。集合可以有重复的元素吗?您需要检查会员资格吗?你处理它们的顺序有关系吗?

这些是您需要回答的问题类型,以便对不同的馆藏类型做出明智的决定。

【讨论】:

    【解决方案3】:

    我假设您正在尝试查找 StartsWithEndWithContains 某个搜索词的匹配项。如果是这种情况,那么您是正确的,List 并不理想。我不相信Hashset 更好。

    查看trie。我不会建立一个,但如果给出有关问题空间的一些上下文。该算法涉及按初始子字符串对单词进行分组 - 根据第一个字母对单词进行分组,然后按第二个字母进行分组,依此类推。

    当我过去这样做时,我既使用了Lookup 类,也实现了Dictionary<string, List<string>>

    我使用的算法大致是

    var dictionary = new Dictionary<int, Lookup<string, string>>();
    for (int i = 1; i < maxWordLength; i++)
    {
        // get all words with i or more letters
        dictionary.Add(i, words.ToLookup(w => w.Substring(i)));
    }
    

    然后找到一个类似的词

    var word = "TestWord";
    var matches = dictionary[word.Length][word];
    

    如果您还需要EndsWithContains,您可能还需要一些索引结构。

    【讨论】:

      【解决方案4】:

      这听起来像是Lucene 的工作。但是,如果您决定实现自己的算法(无论是什么算法),那么最好的办法是利用 C# 在 Parallel.ForEach 和 PLINQ 中强大的并行循环结构。

      Data Parallelism (Task Parallel Library)

      Parallel LINQ (PLINQ)

      var source = Enumerable.Range(100, 20000);
      
      // Result sequence might be out of order.
      var parallelQuery = from num in source.AsParallel()
                          where num % 10 == 0
                          select num;
      

      【讨论】:

        【解决方案5】:

        如果列表是静态的,最好的可能是字符串数组,因为它的开销最低。

        然后使用多个线程。

        【讨论】:

          【解决方案6】:

          进行了测试,没有得到我期望的答案。 List 和 HashSet 和 AsParallel 差不多(但只有 2 核机)。 .NET 4.0 和 600,000 个单词的列表。

          我回应第一条评论。当有疑问时测试。 l 是 List,h 是 HashSet。

          Debug.WriteLine("lWords.Count hWords.Count " + lWords.Count.ToString() + " " + hWords.Count.ToString());
          Stopwatch SW = new Stopwatch();
          SW.Restart();
          Debug.WriteLine("H count " + hWords.Where(value => value.StartsWith("s")).Count().ToString());
          SW.Stop();
          Debug.WriteLine("H time " + SW.ElapsedMilliseconds.ToString());
          SW.Restart();
          SW.Stop();
          Debug.WriteLine("Start Stop " + SW.ElapsedMilliseconds.ToString());
          SW.Restart();
          Debug.WriteLine("L count " + lWords.Where(value => value.StartsWith("s")).Count().ToString());
          SW.Stop();
          Debug.WriteLine("L time " + SW.ElapsedMilliseconds.ToString());
          SW.Restart();
          Debug.WriteLine("H count " + hWords.Where(value => value.StartsWith("s")).Count().ToString());
          SW.Stop();
          Debug.WriteLine("H time " + SW.ElapsedMilliseconds.ToString());
          SW.Restart();
          Debug.WriteLine("L count " + lWords.AsParallel().Where(value => value.StartsWith("s")).Count().ToString());
          SW.Stop();
          Debug.WriteLine("L time parallel " + SW.ElapsedMilliseconds.ToString());
          SW.Restart();
          Debug.WriteLine("H count " + hWords.AsParallel().Where(value => value.StartsWith("s")).Count().ToString());
          SW.Stop();
          Debug.WriteLine("H time parallel " + SW.ElapsedMilliseconds.ToString());
          Debug.WriteLine("");
          
          output:
          lWords.Count hWords.Count 667309 667309
          H count 45851
          H time 283
          Start Stop 0
          L count 45851
          L time 285
          H count 45851
          H time 364
          L count 45851
          L time parallel 307
          H count 45851
          H time parallel 344
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2020-09-19
            • 2011-10-23
            • 2018-07-17
            • 2011-05-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多