我确定这样的事情存在,但我不知道它会被称为什么(或者如何在其上找到更多信息)。如果我有按字母顺序排序的单词列表,并且我正在检查 if 和 where 这个单词" test"在那个列表中,从一开始就没有意义,但从T开始,对吗?当然,数字也一样。有没有办法实现这样的事情并定制搜索的开始?或者hash sets
和[{1}}这样的方法已经自己做了吗?
编辑:
例如,如果我有一个整数列表,如{1,2,3,5,7,8,9,23 ..},是否有任何自动方式对其进行排序,以便在我检查列表时元素" 9",它从一开始就没有开始......?
抱歉,这是一个简单的例子,但我打算通过可能包含数千个元素的列表进行数千次搜索
编辑2:
从回复中,我了解了二进制搜索,但由于这显然是从列表中间开始的,因此可以手动实现某些内容,例如,将一个单词列表拆分为26个单元格,例如当你搜索一个特定的单词时,它可以立即开始在最佳位置搜索(如果每个bin开始变得人口过多,可能会开始搜索52个)。
答案 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
,但如果您要修改列表并且只搜索一次或两次,则会定期IndexOf
或Contains
可能是您最好的选择。
如果您希望按照第一个字母对单词进行分组,我可能会使用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)
当列表排序时,您正在寻找BinarySearch
:http://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
时间,您应该使用IndexOf
或O(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
解决方案更简单,实施更快:)