我有一个由 30 个实数组成的排序数组。数字分布均匀。我想在这个数组中搜索一个数字。目前,我正在使用线性搜索算法。为了提高我的应用程序的性能,我需要使用更好的搜索算法。我应该使用哪种搜索算法或者我应该在什么基础上选择“最佳”算法?
提前致谢!
我有一个由 30 个实数组成的排序数组。数字分布均匀。我想在这个数组中搜索一个数字。目前,我正在使用线性搜索算法。为了提高我的应用程序的性能,我需要使用更好的搜索算法。我应该使用哪种搜索算法或者我应该在什么基础上选择“最佳”算法?
提前致谢!
您没有指定语言,对于仅包含 30 个元素的数组,最快的方法可能会因语言而异。
但是,如果您编写一个测试 C# 程序,您会发现对于 RELEASE 构建,使用BinarySearch()
会更快。C++ 和其他语言可能会给出不同的结果。
以下测试代码使用线性和二进制搜索在 30 个整数的数组中搜索不存在的元素。因为该元素不存在,所以两次搜索都将采用最大数量的操作。成功搜索的结果会有所不同。
结果是这样的:
IndexOf() took 00:00:00.5463193
BinarySearch() took 00:00:00.3035060
表明二分搜索要快一些,至少在目标元素不存在时对于 C# 来说是这样。
int[] array = new int[30];
int count = 10000000;
for (int trial = 0; trial < 4; ++trial)
{
var sw = Stopwatch.StartNew();
for (int i = 0; i < count; ++i)
Array.IndexOf(array, 1);
Console.WriteLine("IndexOf() took " + sw.Elapsed);
sw.Restart();
for (int i = 0; i < count; ++i)
Array.BinarySearch(array, 1);
Console.WriteLine("BinarySearch() took " + sw.Elapsed);
}
你需要做一些时间来确定什么是最快的。这可能因平台、编程语言、CPU 架构、您拥有的数据等而异。还值得对整个程序执行计时,使用分析器或插入您自己的计时调用,只要您认为合适。
为了测试 C++ 中哪种技术最快,我运行了一个简单的测试程序来比较
std::find
) 进行线性搜索,O(n),针对std::lower_bound
),O(log n),针对一旦找到匹配项,对已排序数据的线性搜索就会停止,因此如果您要查找的元素在数组中,则其预期成本是对未排序数组进行线性搜索的一半。在我的测试程序中,我寻找的一半案例不在数组中,因此您预计其成本约为对未排序数据进行线性搜索的成本的 75%。当然,如果您必须经常对数组进行排序,则会大大增加运行时间!
在下图中,
至少在这种情况下,您可以看到,在 n=30 的技术之间没有太多选择,除非分析表明您有真正的性能瓶颈,否则最好遵循保持简单的规则,并且,如果您不必对数据进行排序,只需对未排序的数据进行线性搜索,这样您就没有排序数据的额外约束(或者如果排序是合理的约束,则对排序数据进行线性搜索)。
如果您的数字已排序,您应该使用二进制搜索。与线性搜索(O(n)
)相比,它会O(log n)
及时搜索
首先,您是否完全确定搜索确实代表了瓶颈?在编写代码之前优化您的日程安排,确保您在真正值得的地方进行优化。您很容易会惊讶地发现一些更简单的东西需要更长的时间。我建议进行分析以确保。如果您使用 C++,VerySleepy通常会为我完成这项工作。
现在,如果您注意到搜索确实代表了瓶颈,您可以切换到二进制搜索,如评论中所建议的(在 C++ 中,std::binary_search
来自<algorithm>
)。您也可以为hast table切换容器,但这取决于您的需求和情况。
配置文件,基准测试,选择最适合您的情况。
如果是 30 种原始类型的数组,线性搜索无疑是最佳选择。
对于 Hash :如果您使用 C++ 编程,则可以使用 C++ 容器“Set”。否则,您可以简单地使用数组来完成您必须标记存在的元素的工作。为了搜索它,只需检查该元素的标志是设置还是未设置!