我目前正在尝试使用STL数据结构。然而,我仍然不确定何时使用哪种数据结构以及何时使用某种组合。目前,我正在尝试弄清楚,在什么情况下使用std::multimap
是有意义的。据我所知,人们可以通过组合std::map
和std::vector
来轻松构建自己的multimap实现。因此,我想知道应该在什么情况下使用这些数据结构。
- 简单性:使用
std::multimap
肯定更简单,因为不需要处理额外的嵌套。但是,要将元素范围作为一个整体访问,可能需要将迭代器中的数据复制到另一个数据结构(例如std::vector
)。 - 速度:向量的局部性很可能使得遍历相等元素的范围更快,因为缓存使用得到了优化。但是,我猜测
std::multimaps
也有许多优化技巧,以使遍历相等元素尽可能快。此外,正确获取元素范围可能也会针对std::multimaps
进行优化。
为了测试速度问题,我使用了以下程序进行了一些简单的比较:
#include <stdint.h>
#include <iostream>
#include <map>
#include <vector>
#include <utility>
typedef std::map<uint32_t, std::vector<uint64_t> > my_mumap_t;
const uint32_t num_partitions = 100000;
const size_t num_elements = 500000;
int main() {
srand( 1337 );
std::vector<std::pair<uint32_t,uint64_t>> values;
for( size_t i = 0; i <= num_elements; ++i ) {
uint32_t key = rand() % num_partitions;
uint64_t value = rand();
values.push_back( std::make_pair( key, value ) );
}
clock_t start;
clock_t stop;
{
start = clock();
std::multimap< uint32_t, uint64_t > mumap;
for( auto iter = values.begin(); iter != values.end(); ++iter ) {
mumap.insert( *iter );
}
stop = clock();
std::cout << "Filling std::multimap: " << stop - start << " ticks" << std::endl;
std::vector<uint64_t> sums;
start = clock();
for( uint32_t i = 0; i <= num_partitions; ++i ) {
uint64_t sum = 0;
auto range = mumap.equal_range( i );
for( auto iter = range.first; iter != range.second; ++iter ) {
sum += iter->second;
}
sums.push_back( sum );
}
stop = clock();
std::cout << "Reading std::multimap: " << stop - start << " ticks" << std::endl;
}
{
start = clock();
my_mumap_t mumap;
for( auto iter = values.begin(); iter != values.end(); ++iter ) {
mumap[ iter->first ].push_back( iter->second );
}
stop = clock();
std::cout << "Filling my_mumap_t: " << stop - start << " ticks" << std::endl;
std::vector<uint64_t> sums;
start = clock();
for( uint32_t i = 0; i <= num_partitions; ++i ) {
uint64_t sum = 0;
auto range = std::make_pair( mumap[i].begin(), mumap[i].end() );
for( auto iter = range.first; iter != range.second; ++iter ) {
sum += *iter;
}
sums.push_back( sum );
}
stop = clock();
std::cout << "Reading my_mumap_t: " << stop - start << " ticks" << std::endl;
}
}
正如我所料,这主要取决于num_partitions
和num_elements
的比例,因此我仍然不知所措。以下是一些示例输出:
对于num_partitions = 100000
和num_elements = 1000000
Filling std::multimap: 1440000 ticks
Reading std::multimap: 230000 ticks
Filling my_mumap_t: 1500000 ticks
Reading my_mumap_t: 170000 ticks
对于 num_partitions = 100000
和 num_elements = 500000
Filling std::multimap: 580000 ticks
Reading std::multimap: 150000 ticks
Filling my_mumap_t: 770000 ticks
Reading my_mumap_t: 140000 ticks
当 num_partitions = 100000
且 num_elements = 200000
时
Filling std::multimap: 180000 ticks
Reading std::multimap: 90000 ticks
Filling my_mumap_t: 290000 ticks
Reading my_mumap_t: 130000 ticks
当 num_partitions = 1000
并且 num_elements = 1000000
时
Filling std::multimap: 970000 ticks
Reading std::multimap: 150000 ticks
Filling my_mumap_t: 710000 ticks
Reading my_mumap_t: 10000 ticks
我不确定如何解读这些结果。你是如何决定正确的数据结构的?是否还有其他决策的限制,我可能会错过了什么?
std::multimap
解决方案。 - LiKaomultimap
更适合被描述为一个list
的map
而不是一个vector
的map
。 - CAFxX