说实话,我有点困惑。我正在研究经典算法问题之一。给定一个整数集合,找到是否有2个元素加和成给定的数字。
因此,我已经实现了2个解决方案。
bool find1(std::vector<int>& V, int sum)
{
std::unordered_set<int> hashTable;
for (int i = 0; i < V.size(); ++i)
{
if (hashTable.find(V[i]) != hashTable.end())
{
return true;
}
hashTable.insert(sum - V[i]);
}
return false;
}
bool find2(std::vector<int>& V, int sum)
{
for (int i = 0; i < V.size() ; ++i)
{
if (std::binary_search(V.begin(), V.end(), sum - V[i]))
{
return true;
}
}
return false;
}
Find1有望成为一种线性算法(取决于存储桶的负载和哈希函数的效率)。
Find2预期为NlogN,我们循环并为每次迭代进行二进制搜索。
实现此功能后,我尝试在相对较大的集合上测试这些算法的运行时间,结果使我感到困惑。
int main()
{
std::vector<int> V(10000,0);
std::chrono::system_clock::time_point now1 = std::chrono::system_clock::now();
for (int i = 0; i < 100; ++i)
{
bool b = find1(V, 1000);
}
std::chrono::system_clock::time_point then1 = std::chrono::system_clock::now();
std::cout <<"Linear with hashing = "<< std::chrono::duration_cast<std::chrono::microseconds>(then1 - now1).count()<<std::endl;
std::chrono::system_clock::time_point now2 = std::chrono::system_clock::now();
std::sort(V.begin(), V.end());
for (int i = 0; i < 100; ++i)
{
bool b = find2(V, 1000);
}
std::chrono::system_clock::time_point then2 = std::chrono::system_clock::now();
std::cout <<"NlogN with binary_search = " <<std::chrono::duration_cast<std::chrono::microseconds>(then2 - now2).count() << std::endl;
system("pause");
}
在这里,我将vector
初始化为0,以确保两个算法都在最坏的情况下运行。
该程序的输出为:
Linear with hashing = 6759245
NlogN with binary_search = 4508025
这怎么可能?有人可以向我解释一下吗?
答案 0 :(得分:9)
一种算法的渐近复杂度的上限小于另一种算法,但这并不意味着它对于任何任意输入都更快。这仅意味着存在一定大小的输入N'
,超过此大小,较简单的算法将更快。此大小将特定于运行该程序的每个特定系统。
将渐近复杂算法测得更快意味着,您的测试小于N'
。但是,这假定您的复杂性分析首先适用于该程序。例如,如果程序使用最佳情况下的输入来测试算法,则分析最坏情况下的复杂性是错误的,反之亦然。
对于它的价值,在我的系统上的结果是:
Linear with hashing = 9557
NlogN with binary_search = 15828
答案 1 :(得分:6)
您创建的哈希表没有预期的大小。然后,将元素逐一插入。这会导致哈希表的大小一遍又一遍地调整,从而导致系统调用分配更多的内存。
虽然每次插入时这些费用全部摊销O(1)
,但系统调用的隐藏常量足够大,可以使二进制搜索更快。
尝试将哈希表的预期大小设置为sizeof(V) * 1.2
左右,以避免重新哈希。如果还不够,则将计时与100000, 1000000, 10000000, ...
值进行比较。您应该会看到随着N
变大,哈希表获胜。
注意:使用V.end() == 0
进行二进制搜索将在第一次比较时终止,这不是最坏的情况。最好的情况。可能是更快的原因。
答案 2 :(得分:2)
O(N)比O(N Log N)渐近快。这并不意味着它会更快。
查看Big-O表示法的定义。