【发布时间】:2014-05-29 15:48:46
【问题描述】:
我正在尝试在键值对的排序向量上实现查找方法。现在它的执行速度比 map.find(key) 慢。理论上它应该更快,因为向量可以更好地利用 CPU 缓存,因为它的内存是连续的。我只是想知道这个实现是否有任何明显的问题,是否有任何方法可以优化它?我不认为在这里使用标准算法是一个选项,因为最接近的可能选项是 lower_bound ,这将导致我必须执行检查以验证它是否找到任何东西的额外开销。除此之外,lower_bound 将需要我构建一个 pair(加上我在它周围放置的包装器)以将其作为我正在搜索的值,从而产生更多不必要的开销。
FlatMap<KEY, VALUE, COMPARATOR>::findImp(const key_type &key)
{
typename VectorType::iterator lower = d_elements.begin();
typename VectorType::iterator upper = d_elements.end();
typename VectorType::iterator middle;
while(lower < upper) {
middle = lower + (upper-lower)/2;
if(d_comparator(middle->data().first, key)){
lower = middle;
++lower;
} else if(d_comparator(key, middle->data().first)){
upper = middle;
} else {
return middle;
}
}
return d_elements.end();
}
请注意,d_elements 是对的向量(对在包装器中):
vector<FlatMap_Element<KEY, VALUE> > d_elements;
包装器本身只是将这对作为数据成员保存,并通过不应该影响搜索的赋值来做一些魔术:
template <class KEY, class VALUE>
class FlatMap_Element {
bsl::pair<const KEY, VALUE> d_data;
...
pair<const KEY, VALUE>& data();
pair<const KEY, VALUE> const& data() const;
};
我知道使用包装器的业务不是减速的原因,因为我已经在没有包装器的向量或对上测试了该算法并且具有相同的性能。
感谢任何调整建议。
【问题讨论】:
-
一个明显的改进是只使用一次 d_comparator。从理论上讲,您调用某个给定两个值返回 -1、0 或 1 的函数,并使用该信息重新分配您的界限。显然,您的比较器的工作方式不同,因为如果一个参数大于另一个参数,它返回
true,否则返回false。我会考虑切换到只能调用一次的比较器,看看它是否有什么不同。 -
您拒绝
std::lower_bound的最终相等性测试,而您的版本在每次迭代时都进行检查... -
使用
middle = (lower+upper)/2;而不是middle = lower + (upper-lower)/2;可能会减少一点算术。 -
“下限在每次迭代时都会进行完全相同的检查”。如果您已通过查看源代码验证了这一点,consider switching to an implementation that does it right。
-
不要假设没有基准测试的 lower_bound 太慢。事实上,如果没有基准测试/分析,不要假设任何事情。每当您开始猜测性能时,很有可能会出错。
标签: c++ performance algorithm vector