如何快速搜索单词或数字c#

时间:2014-09-13 06:34:38

标签: c# performance search

我确定这样的事情存在,但我不知道它会被称为什么(或者如何在其上找到更多信息)。如果我有按字母顺序排序的单词列表,并且我正在检查 if where 这个单词" test"在那个列表中,从一开始就没有意义,但从T开始,对吗?当然,数字也一样。有没有办法实现这样的事情并定制搜索的开始?或者hash sets和[{1}}这样的方法已经自己做了吗?

编辑:

例如,如果我有一个整数列表,如{1,2,3,5,7,8,9,23 ..},是否有任何自动方式对其进行排序,以便在我检查列表时元素" 9",它从一开始就没有开始......?

抱歉,这是一个简单的例子,但我打算通过可能包含数千个元素的列表进行数千次搜索

编辑2:

从回复中,我了解了二进制搜索,但由于这显然是从列表中间开始的,因此可以手动实现某些内容,例如,将一个单词列表拆分为26个单元格,例如当你搜索一个特定的单词时,它可以立即开始在最佳位置搜索(如果每个bin开始变得人口过多,可能会开始搜索52个)。

2 个答案:

答案 0 :(得分:3)

如果您说有一个排序列表并且想要搜索它,那么立即跳转到 my 头脑的算法就是二进制搜索。幸运的是List<T> already has that implemented

该链接上的示例实际上看起来完全符合您的要求(它也在处理在排序单词列表中查找单词)。

从本质上讲,你想要这样的东西:

List<string> words = ...;

words.Sort(); // or not depending on the source

var index = words.BinarySearch("word");

if(index > -1)
{
    // word was found, and its index is stored in index
}
else // you may or may not want this part
{    // this will insert the word into the list, so that you don't have to re-sort it.
    words.Insert(~index, "word");
}

当然,这也适用于int。只需将List<string>替换为List<int>,将BinarySearch参数替换为int

大多数Contains - 类型的函数只是遍历集合,直到遇到您正在寻找的项目。这非常有效,因为您不必先对集合进行排序,但是当您开始排序时它并不是那么好。因此,在大多数情况下,如果您经常搜索相同的列表,请对其进行排序并BinarySearch,但如果您要修改列表并且只搜索一次或两次,则会定期IndexOfContains可能是您最好的选择。


如果您希望按照第一个字母对单词进行分组,我可能会使用Dictionary<char, List<string>>来存储它们。我为了可变性而在数组上选择List,因此请自行调用 - 如果您选择使用数组,也可以Array.BinarySearch。您可以进入专有树模型,但这可能是也可能不是过度杀伤。要做第一个字符键入的字典,你需要这样的东西:

Dictionary<char, List<string>> GetDict(IEnumerable<string> args)
{
    return args.GroupBy(c => c[0]).ToDictionary(c => c.Key, c => c.OrderBy(x => x).ToList());
}

然后你就可以非常简单地使用它,就像以前一样。唯一的变化将在于获取列表。

Dictionary<char, List<string>> wordsByKey = GetDict(words);
List<string> keyed;
string word = "word";

if (wordsByKey.TryGetValue(word[0], out keyed))
{
    // same as before
}
else
{
    wordsByKey.Add(word[0], new List<string>() { word }); // or not, again
                                                          // depending on whether you
                                                          // want the list to update.
}

答案 1 :(得分:1)

当列表排序时,您正在寻找BinarySearchhttp://msdn.microsoft.com/pl-pl/library/3f90y839%28v=vs.110%29.aspx。在简单Contains中,复杂度为O(log n)对O(n)。

List<string> myList = GetList();
string elementToSearch = "test";

if (myList.Contains(elementToSearch)) 
{
    // found, O(n), works on unsorted list
}

if (myList.BinarySearch(elementToSearch)) >= 0)
{
    // found, O(log n), works only on sorted list
}

要谨慎:What is the difference between Linear search and Binary search?

要编辑:

如果您的输入集合未排序,则由于提及Contains时间,您应该使用IndexOfO(n)。它会循环你的收藏一次。排序集合效率较低 - 需要O(n log n)。为了搜索一个元素,对它进行排序效率不高。

一些实现pefromance的样本:

var r = new Random();
var list = new List<int>();

for (var i = 1; i < 10000000; i++)
{
    list.Add(r.Next());
}

// O (log n) - we assume that list is sorted, so sorting is pefromed outside watch
var sortedList = new List<int>(list);
sortedList.Sort();

var elementToSearch = sortedList.Last();

var watcher = new Stopwatch();
watcher.Start();
sortedList.BinarySearch(elementToSearch);
watcher.Stop();
Console.WriteLine("BinarySearch on already sorted: {0} ms",
                           watcher.Elapsed.TotalMilliseconds);

// O(n) - simple search
elementToSearch = list.Last();
watcher.Reset();
watcher.Start();
list.IndexOf(elementToSearch);
watcher.Stop();
Console.WriteLine("IndexOf on  unsorted: {0} ms",
                     watcher.Elapsed.TotalMilliseconds);

// O(n log n) + O (log n)
watcher.Reset();
watcher.Start();
list.Sort();
elementToSearch = list.Last();
list.BinarySearch(elementToSearch);
watcher.Stop();
Console.WriteLine("Sort + binary search on unsorted: {0} ms"
                    , watcher.Elapsed.TotalMilliseconds);

Console.ReadKey();

结果:

  

BinarySearch on已排序:0.0248 ms

     

未分类的IndexOf:6.144 ms

     

排序+未分类的二进制搜索:1157.3298 ms

编辑以编辑2: 我认为你正在寻找BucketSort而是: 您可以自己实现它,但我认为 Matthew Haugen Dictionary解决方案更简单,实施更快:)