我有一张无序的地图,就像:
std::unordered_map < std::string, std::vector<std::string> > m_unordered_map;
在其中插入值时,以下哪一项会更快,为什么?
方法1(骨架):
std:string key = "key";
for (int i = 0; i < n; ++i) {
std::string value = std::to_string(i); // Value would be acually an big string.
m_unordered_map[key].push_back(value1);
}
方法2(骨架)
std:string key = "key";
std::vector<std::string> vec;
for (int i = 0; i < n; ++i) {
std::string value = std::to_string(i); // Value would be acually an big string.
vec.insert(value);
}
m_unordered_map.insert({key, vec});
或者有更好的方法吗?
答案 0 :(得分:4)
假设您事先知道一些事情的关键,那么您拥有的第二个版本会更好,因为它避免了在每次迭代上进行地图查找。
您可以通过移动而不是复制字符串和向量来进一步改进它。例如
std::string key = "key";
std::vector<std::string> vec;
for (int i = 0; i < 10; ++i) {
vec.emplace_back(std::to_string(i));
}
m_unordered_map.emplace(key, std::move(vec));
通常:
unordered_map
之类的键尤其是访问std::string
仍然相当缓慢。对于“命中”,将花费键长度上的O(n)哈希值和O(n)字符串比较。哈希表本身不只是O(1)。如果您只能访问它一次,则可能保留一个更快的迭代器/引用(请检查迭代器失效规则。insert
可能会使unordered_map
中的其他迭代器失效,因此请小心,但它不会t使对值的引用无效)。如果您可以用一个整数ID完全替换字符串,那么通常也会更快。答案 1 :(得分:1)
改善两种方法:
方法1(骨架):
std:string key = "key";
auto& vec = m_unordered_map[key];
vec.reserve(n);
for (int i = 0; i != n; ++i) {
vec.push_back(std::to_string(i));
}
方法2(骨骼)
std:string key = "key";
std::vector<std::string> vec;
vec.reserve(n);
for (int i = 0; i != n; ++i) {
vec.push_back(std::to_string(i));
}
m_unordered_map[key] = std::move(vec));
所以
在我这边,我将创建一种方法来构建矢量,例如:
std::vector<std::string> create_iota_strings(std::size_t n)
{
std::vector<std::string> vec;
vec.reserve(n);
for (std::size_t i = 0; i != n; ++i) {
vec.push_back(std::to_string(i));
}
return vec;
}
然后简单
m_unordered_map[key] = create_iota_strings(n);
如果您知道密钥不存在,那么 insert
/ emplace
可能比operator[]
更合适。
如果可能存在密钥try_emplace
将是避免构造空向量的解决方案(当密钥不存在时)。