查找 vs equal_range 和性能
Posted
技术标签:
【中文标题】查找 vs equal_range 和性能【英文标题】:find vs equal_range and performance 【发布时间】:2013-08-06 13:45:36 【问题描述】:我正在使用 find、equal_range 和我自己的二进制搜索函数进行一些测试,但我无法理解为什么与 find 相比,equal_range 需要这么长时间。
我有一个已排序的向量,并为搜索操作的持续时间计时。最初的想法是看看 find 和 equal_range 之间的性能差异是什么,但我预计随着数据量的增长,在向量上迭代会比二分搜索更糟糕,但这并没有发生。
我的代码很简单,但我“怀疑”这里出了点问题,我不知道是什么。
-- 编辑 -- 我在 VS2012 中做这些测试 --
#include "stdafx.h"
#include <vector>
#include <algorithm>
#include <chrono>
#include <iostream>
#include <list>
using namespace std;
#define TIMING
#ifdef TIMING
#define INIT_TIMER auto start = std::chrono::high_resolution_clock::now();
#define START_TIMER start = std::chrono::high_resolution_clock::now();
#define STOP_TIMER(name) std::cout << name << ": " << \
std::chrono::duration_cast<std::chrono::nanoseconds>( \
std::chrono::high_resolution_clock::now()-start \
).count() << " ns " << std::endl;
#else
#define INIT_TIMER
#define START_TIMER
#define STOP_TIMER(name)
#endif
template<typename T> int mybsearch(const std::vector<T>& vec, unsigned start, unsigned end, const T& key)
// Termination condition: start index greater than end index
if(start > end)
return -1;
// Find the middle element of the vector and use that for splitting
// the array into two pieces.
unsigned middle = start + ((end - start) / 2);
if(vec[middle] == key)
return middle;
else if(vec[middle] > key)
return mybsearch(vec, start, middle - 1, key);
return mybsearch(vec, middle + 1, end, key);
template<typename Iterator, typename T> Iterator Tbsearch(Iterator& begin, Iterator& end, const T& key)
// Keep halving the search space until we reach the end of the vector
Iterator NotFound = end;
while(begin < end)
// Find the median value between the iterators
Iterator Middle = begin + (std::distance(begin, end) / 2);
// Re-adjust the iterators based on the median value
if(*Middle == key)
return Middle;
else if(*Middle > key)
end = Middle;
else
begin = Middle + 1;
return NotFound;
int _tmain(int argc, _TCHAR* argv[])
vector<int> V;
typedef vector<int>::iterator it;
std::pair<it,it> res;
it val;
list<int> L;
typedef list<int>::iterator itL;
std::pair<itL,itL> lpair;
itL lval;
for(int i=0; i<1000000; i++)
V.push_back(i+1);
L.push_back(i+1);
INIT_TIMER
cout << "-- find --\n";
for(int k=0;k<10;k++)
int look = pow(k,k);
START_TIMER
val = std::find(V.begin(),V.end(),look);
STOP_TIMER("find took ")
if(val!=V.end())
cout << look << " found\n";
else
cout << look << " not found\n" ;
cout << "-- homemade bsearch (index) --\n";
for(int k=0;k<10;k++)
int look = pow(k,k);
START_TIMER
int a = mybsearch(V, 0, V.size()-1, look);
STOP_TIMER("find took ")
if(a>0)
cout << look << " found\n";
else
cout << look << " not found\n" ;
cout << "-- homemade bsearch (iterators) --\n";
for(int k=0;k<10;k++)
int look = pow(k,k);
START_TIMER
it f = Tbsearch(V.begin(), V.end(), look);
STOP_TIMER("find took ")
if(f!=V.end())
cout << look << " found\n";
else
cout << look << " not found\n" ;
cout << "-- equal range --\n";
for(int k=0;k<10;k++)
int look = pow(k,k);
START_TIMER
res = std::equal_range(V.begin(),V.end(),look);
STOP_TIMER("equal_range took ")
if(res.first!=res.second)
cout << look << " found\n";
else
cout << look << " not found\n" ;
return 0;
本次运行的输出是
-- find --
find took : 0 ns
1 found
find took : 0 ns
1 found
find took : 0 ns
4 found
find took : 0 ns
27 found
find took : 0 ns
256 found
find took : 0 ns
3125 found
find took : 0 ns
46656 found
find took : 2000200 ns
823543 found
find took : 2000200 ns
16777216 not found
find took : 2000200 ns
387420489 not found
-- homemade bsearch (index) --
find took : 0 ns
1 not found
find took : 0 ns
1 not found
find took : 0 ns
4 found
find took : 0 ns
27 found
find took : 0 ns
256 found
find took : 0 ns
3125 found
find took : 0 ns
46656 found
find took : 0 ns
823543 found
find took : 0 ns
16777216 not found
find took : 0 ns
387420489 not found
-- homemade bsearch (iterators) --
find took : 0 ns
1 found
find took : 0 ns
1 found
find took : 0 ns
4 found
find took : 0 ns
27 found
find took : 0 ns
256 found
find took : 0 ns
3125 found
find took : 1000100 ns
46656 found
find took : 1000100 ns
823543 found
find took : 0 ns
16777216 not found
find took : 0 ns
387420489 not found
-- equal range --
equal_range took : 683068300 ns
1 found
equal_range took : 681068100 ns
1 found
equal_range took : 681068100 ns
4 found
equal_range took : 679067900 ns
27 found
equal_range took : 679067900 ns
256 found
equal_range took : 680068000 ns
3125 found
equal_range took : 683068300 ns
46656 found
equal_range took : 677067700 ns
823543 found
equal_range took : 680068000 ns
16777216 not found
equal_range took : 678067800 ns
387420489 not found
干杯
【问题讨论】:
equal_range 实际上不太可能花费半秒以上的时间来完成一百万个项目的向量。运行程序时,您是否注意到控制台上的这种延迟?这种方式的计时函数也容易产生不正确的值。 您使用的是优化版本吗? @juanchopanza,不,我正在使用调试版本 嗯,好的。调试版本上的这种类型的测量是没有意义的。另外,关于大卫所说的,也许可以延长测试时间并以毫秒为单位进行测量。 @Candag:总是在发布/优化版本中衡量,因为这很重要。更长的答案是模板从优化(内联)中受益匪浅,因此在比较两个模板解决方案时,根据您的优化方式,您可能会得到截然不同的性能结果(甚至比率)。 【参考方案1】:在 VS2012 的调试版本中我得到了
-- equal range --
equal_range took : 796079600 ns
1 found
equal_range took : 792079200 ns
1 found
equal_range took : 785078500 ns
4 found
equal_range took : 786078600 ns
27 found
equal_range took : 785078500 ns
256 found
equal_range took : 784078400 ns
3125 found
equal_range took : 785078500 ns
46656 found
equal_range took : 786078600 ns
823543 found
equal_range took : 784078400 ns
16777216 not found
equal_range took : 784078400 ns
387420489 not found
而在发布版本中我得到了
-- equal range --
equal_range took : 0 ns
1 found
equal_range took : 0 ns
1 found
equal_range took : 0 ns
4 found
equal_range took : 0 ns
27 found
equal_range took : 0 ns
256 found
equal_range took : 0 ns
3125 found
equal_range took : 0 ns
46656 found
equal_range took : 0 ns
823543 found
equal_range took : 0 ns
16777216 not found
equal_range took : 0 ns
387420489 not found
调试版本中的迭代器检查会减慢它的速度。
【讨论】:
以上是关于查找 vs equal_range 和性能的主要内容,如果未能解决你的问题,请参考以下文章
用于关联容器的 C++ 入门 5ed equal_range
使用 `std::equal_range` 和 `boost::transform_iterator`
equal_range 和 2 重载对“this”指针没有合法转换