C++ 跟踪std::map::find调用中的节点遍历?

C++ 跟踪std::map::find调用中的节点遍历?,c++,optimization,map,std,C++,Optimization,Map,Std,我正在std::map上执行大量的查找、插入和删除操作。我正在考虑添加一些代码以优化速度,但我想收集一些有关当前工作负载的统计信息。具体地说,我想记录每次调用“find”必须遍历多少个节点,这样我就可以保持一个运行记录 我在想,如果我的映射中的大多数更改发生在最前面,我最好先搜索前N个条目,然后再使用“find”使用的树。如果您的键/值结构可行,那么值得考虑无序映射(在C++11或TR1中)作为替代方案std::map,作为一个平衡树,在这种使用模式下不太可能表现良好,对于我来说,搜索前N个元素

我正在std::map上执行大量的查找、插入和删除操作。我正在考虑添加一些代码以优化速度,但我想收集一些有关当前工作负载的统计信息。具体地说,我想记录每次调用“find”必须遍历多少个节点,这样我就可以保持一个运行记录


我在想,如果我的映射中的大多数更改发生在最前面,我最好先搜索前N个条目,然后再使用“find”使用的树。

如果您的键/值结构可行,那么值得考虑
无序映射
(在C++11或TR1中)作为替代方案
std::map
,作为一个平衡树,在这种使用模式下不太可能表现良好,对于我来说,搜索前N个元素的混合方法似乎需要做很多工作,而且没有保证回报。

Find必须使用map的compare函数来比较元素,这样您就可以提供一个自定义的compare函数来计算它被调用的次数,以查看它在每次调用中做了多少工作(基本上是遍历多少个节点)

我不知道在调用find()之前搜索前N个条目在这种情况下会有什么帮助。遍历映射中的条目只是按排序顺序遍历树,因此它不会比调用find()更有效,除非您的比较函数比检查相等要昂贵得多

示例代码:

#include <algorithm>
#include <iostream>
#include <map>
#include <numeric>
#include <vector>

using namespace std;

int main() {
    vector<int> v(100);
    iota(begin(v), end(v), 0);
    vector<pair<int, int>> vp(v.size());
    transform(begin(v), end(v), begin(vp), [](int i) { return make_pair(i, i); });

    int compareCount = 0;
    auto countingCompare = [&](int x, int y) { ++compareCount; return x < y; };
    map<int, int, decltype(countingCompare)> m(begin(vp), end(vp), countingCompare);
    cout << "Compares during construction: " << compareCount << "\n";
    compareCount = 0;
    auto pos = m.find(50);
    cout << "Compares during find(): " << compareCount << "\n";
}
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
int main(){
向量v(100);
iota(开始(v)、结束(v)、0);
向量vp(v.size());
变换(begin(v)、end(v)、begin(vp),[](inti){返回make_对(i,i);});
int compareCount=0;
自动计数比较=[&](int x,int y){++compareCount;返回x如果你有这样一个特定的假设,你就不能实现两个替代方案并比较它们的性能吗?@BjörnPollex:这个问题是问如何比较它们的性能改变所有代码以使用替代方案的实现将是一项艰巨的工作。我想收集一些关于当前代码的统计数据,看看是否它甚至值得实现。排序很重要,所以我不能使用无序映射。如果我通常查找的元素恰好位于第一个元素附近,则效率可能会更高。例如:1000对(1,X)->(1000,Y)的映射,我在其中进行了20000次查找,但19000次查找最终是针对(1,X)的rest在rest上随机分布。但是使用begin()和end()按排序顺序遍历映射中的元素只是遍历与find()遍历相同的树结构,但没有比较检查以避免无法包含元素的子树。这怎么可能更快呢?我以为查找是O(logN)?它们总是从开头开始吗?如果绝大多数查找实际上是第一个元素,那么您可能会看到一些时间节省,这是真的。一旦您从那里开始迭代,尽管您很快就会失去任何优势-您正在按顺序遍历二元搜索树,因此您必须通过不断增加的不可恢复的元素来跟踪链接每次前进到后续元素时,都要使用vant中间节点。使用find()你必须从根开始,但一定不要一路穿过任何不必要的中间节点。实际上,你的映射有多大?虽然红黑树的渐进复杂性在你进行大量插入和删除时是好的,但它通常也有很差的空间局部性,并进行大量的分配和自由活动s、 实际上,对于许多实际工作负载,使用二进制搜索查找基于排序向量的映射速度更快,例如boost flat_map:。