什么算法用于搜索单词中的子词?

时间:2011-12-10 12:37:59

标签: c# algorithm search word

我知道,也许这个问题很愚蠢但是我被困住了,我需要真正的帮助。我需要在我的项目中使用算法,它可以找到所有单词从另一个单词开始并返回所有单词的尾部。例如: 查找所有以dad

开头的单词

在词典中我们有:

dada, dadaism, daddled, daddling

结果:

a, aism, dled, dling

我有所有单词的字典,所以我需要的只是算法。有人建议我使用patricia算法,但我找不到任何C#样本。我的字典很大,所以我需要找到非常快的算法。


更多信息:

  • 字典已排序。
  • 6 个答案:

    答案 0 :(得分:3)

    这听起来像是Trie / DAWG(有向非循环字图)的完美用法。据我所知,帕特里夏树是一种类似于特里的变体。有a nice article about Tries and an implementation here

    答案 1 :(得分:3)

    如何完成这项工作取决于词典的排列方式。如果它是一个排序的单词列表,那么您可以使用二进制搜索来查找以“dad”开头的第一个单词,然后循环使用StartsWithSubstring的单词。那就是:

    List<string> Words = LoadWords(); // however you load them
    Words.Sort();
    
    // Now, search for "dad" (or whatever)
    string prefix = "dad";
    
    int index = Words.BinarySearch(prefix);
    
    // If the returned index is negative, the word wasn't found.
    // The index is the one's compliment of the the place where it would be in the list.
    if (index < 0)
    {
        index = ~index;
    }
    
    for (int i = index; i < Count && Words[i].StartsWith(prefix))
    {
        Console.WriteLine(Words[i].Substring(prefix.Length));
    }
    

    这应该非常快。排序是加载后的一次性成本。如果按排序顺序存储字典,则可以完全消除它。二进制搜索是O(log n),其中n是字典中的单词数。

    如果你的词典是无序的,那么你将不得不翻阅所有的词,这将花费很多时间。

    您的词典还有其他组织,这将使它占用更少的空间,并且可能更快。这些更复杂,并且比创建排序列表花费更多时间。

    答案 2 :(得分:1)

    我所知道的最着名的是"knuth morris pratt string matching algorithm"

    如果你看一下链接,还有其他一些像Boyer-Moore字符串搜索算法,...... 这些是通用算法,但如果您对特殊情况感兴趣,比如开始,...在大多数情况下,语言都有这种情况,例如在C#中你可以使用StartsWithEndsWith,没有需要再次实施它们。

    答案 3 :(得分:1)

    对于非常小的词典,for循环可能非常快。但是如果你有来自成千上万个单词的匹配集,那将非常慢。假设您的字典已排序(如果没有排序),您可以使用BinarySearch函数找到第一个和最后一个范围项,然后使用for循环来创建结果。

    为了更实际,我有一个(排序的)字典,包含354984个单词,包括从爸爸开始的35个单词:爸爸,爸爸,达达,达达主义,达达主义,达达主义者,达达主义者,达达主义者,达达主义者,爸爸,爸爸,爸爸,爸爸,爸爸,爸爸,爸爸,爸爸,爸爸,爸爸,爸爸,爸爸,爸爸,爸爸,爸爸,dade,dadenhudd,dading,dado,dadoed,爸爸,dadoing,爸爸,爸爸,爸爸和爸爸。如果我遵循Jim的方法,我将不得不执行35“StartsWith”,这是好的。在“sat”前缀的情况下,我有228个单词,如果是“cat”前缀,我有692个单词。对于我的字典大小,我需要总共40个字符串比较(最坏的情况)来找到第一个和最后一个项目。

    如果您愿意使用任何trie实现,请确保如果您的字典包含第1或实时记录,则至少支持数字和短划线。

    答案 4 :(得分:0)

    您可以使用TRIE。您可以找到全面的实施和教程here

    基本上,在这个结构中,你将最终从Root到'd'然后到'a'然后再到'd'。你会想到所有以'dad'开头的单词。现在将其视为根节点,您所要做的就是探索下面的所有可能路径,然后进行算法

    答案 5 :(得分:0)

    如果您需要简单的东西,可以试试这个:

            string[] dict = new string[] { "dada", "dadaism", "daddled", "daddling" };
            string prefix = "dad";
    
            var words = from d in dict
                        where d.StartsWith(prefix)
                        select d.Substring(prefix.Length);