c++ 向量函数的时间复杂度实际上比u_map快

xu3bshqb  于 2023-01-18  发布在  其他
关注(0)|答案(1)|浏览(115)

我不懂逻辑。我有两个元素计数相同的容器:vectorunordered_map
我正在使用一个函数来检查某个函数的时间复杂度,并以毫秒为单位返回值

auto funcComplexity = [](auto&& func, auto&&... params)
{
    const auto& start = high_resolution_clock::now();
    for (auto i = 0; i < 100; ++i) 
    {
        // function invocation using perfect forwarding
        std::forward<decltype(func)>(func)(std::forward<decltype(params)>(params)...);
    }
    const auto& stop = high_resolution_clock::now();
    
    return duration_cast<duration<double, std::milli>>(stop - start).count();
};

当我擦除vector中间的元素时,实际上比擦除unordered_map中的元素要少

void iterateUMap(std::unordered_map<int, Test> map)
{
    map.erase(500);
}

void iterateVector(std::vector<Test> vector)
{
    std::remove_if(vector.begin(), vector.end(), [](Test& val)
        {
            return val.mId == 500;
        });
}

int main()
{
    auto funcComplexity = [](auto&& func, auto&&... params)
    {
        const auto& start = high_resolution_clock::now();
        for (auto i = 0; i < 10000; ++i) 
        {
            // function invocation using perfect forwarding
            std::forward<decltype(func)>(func)(std::forward<decltype(params)>(params)...);
        }
        const auto& stop = high_resolution_clock::now();
    
        return duration_cast<duration<double, std::milli>>(stop - start).count();
    };

    std::unordered_map<int, Test> uMap;

    for(int i = 0; i < 1000; i++)
    {
        uMap.try_emplace(i, Test(i));
    }

    std::vector<Test> vector;
    vector.reserve(1000);
    for (int i = 0; i < 1000; i++)
    {
        vector.emplace_back(i);
    }

    cout << funcComplexity(iterateUMap, uMap) << endl;

    cout << endl;

    cout << funcComplexity(iterateVector, vector) << endl;
      
    return 0;
}

所以这两个函数的输出是:
对于向量为:52.6565毫秒
对于U_Map为:6740.64毫秒
为什么从u_map中删除实际上比从vector中删除要慢?当我只想得到element时也会发生同样的事情。例如:

void iterateUMap(std::unordered_map<int, Test> map)
{
    map[500].DoSomething();
}

void iterateVector(std::vector<Test> vector)
{
    for (auto& value : vector)
    {
        if(value.mId == 500)
        {
            value.DoSomething();
            break;
        }
    }
}
e5nszbig

e5nszbig1#

你刚刚发现了现代计算机硬件的一个秘密。
现代的CPU非常非常擅长线性访问内存,比如向量中的数据是如何存储的,访问X线性内存地址比访问X随机内存地址快几个数量级;并且在观察到这一点之前X不必变得非常大。
这是因为,一般来说,内存是以相对较大的块从RAM中检索的,然后存储在快速的CPU上的缓存中。大块内存块被缓存,访问下一个字节或字将命中快速的CPU上的缓存,而不会导致相对较慢的RAM访问。甚至在访问下一个字节或字之前,当CPU忙碌消化第一对字节时,CPU的不同部分将预先获取下一高速缓存行,从而预测未来的存储器访问。

相关问题