在其他地图值中查找元素的最佳方法是啥?
Posted
技术标签:
【中文标题】在其他地图值中查找元素的最佳方法是啥?【英文标题】:what's the best way to find the element occurs in other map value?在其他地图值中查找元素的最佳方法是什么? 【发布时间】:2021-02-09 06:28:58 【问题描述】:我尝试在地图值中找到也出现在其他值中的元素。
1: ["a", "b", "c", "d"],
2: ["a", "c"],
3: ["c", "d"],
4: ["a", "c"]
=>
"a": [ 1, 2, 4 ], // a occurs in the map which key are 1/2/4
"b": [ 1 ],
"c": [ 1, 2, 3, 4],
"d": [ 1, 3 ]
我的实现是:
map<int, set<string>> map1 =
1, set<string>"a", "b", "c", "d" ,
2, set<string>"a", "c" ,
3, set<string>"c", "d" ,
4, set<string>"a", "c" ,
;
map<string, set<int>> map2;
for (const auto& [id, str_set] : map1)
for (const auto& s : str_set)
if (map2.count(s) == 0)
map2[s] = std::set<int>id;
else
map2[s].emplace(id);
看起来效率不高。那么有没有其他方法可以加快速度呢? 或者是否有任何适当的数据结构/算法来处理我想要的这些数据?
【问题讨论】:
Looks like it's not efficient
为什么?
@ShridharRKulkarni 我只是不喜欢嵌套
除此之外:你不需要if
,map2[s].emplace(id);
在这两种情况下都是正确的
Is your question answered?
【参考方案1】:
使用无序映射和无序集。平均案例常数时间搜索。
您可以用空间换取更快的速度。创建一个布尔矩阵键与值。 O(1) 搜索。
【讨论】:
【参考方案2】:如果您确实需要“更快”,并且您可以对输入做出一些假设,即 1) 键都是数字并且只是从 1 开始计数,并且 2) 您只有单个字母作为值,那么您可以将整个(小写)字母表放入 int 的位中,您可以使用向量。
但如果这太过分了,我同意之前的回答,哈希表比地图更好(所以使用 unordered_* 版本的地图和集合)。比集合更好的是向量(在这种情况下)。您可以使用 char 向量作为集合,以字母作为索引,并设置 1 表示“存在”。这就像上面存储在一个 int 中的 bitset 版本,但是在一个真实的容器中,这可能更受欢迎。
还有,你的这段代码:
if (map2.count(s) == 0)
map2[s] = std::set<int>id;
else
map2[s].emplace(id);
写得更好:
map2[s].emplace(id);
注意:对于地图和集合(以及无序的地图和集合),如果元素不存在,operator[] 将创建该元素,因此您无需进行初始化集合的工作。
【讨论】:
【参考方案3】:如果您有权访问 Boost 库,则可以使用 boost::bimap
组合您的两个地图。
boost::bimap<boost::bimaps::multiset_of<int>, boost::bimaps::multiset_of<std::string>> map;
map.insert(1, "a");
...
map.insert(4, "c");
然后您可以使用map.left
按数字查找,使用map.right
按字符串查找
【讨论】:
【参考方案4】:如果您确实需要“更快”,并且您可以对输入做出一些假设,即 1) 键都是数字并且只是从 1 开始计数,并且 2) 您只有单个字母作为值,那么您可以将整个(小写)字母表放入 int 的位中,并将其用作一个集合。使用此类整数的向量,您可以通过扫描向量并测试位来构建输出,如果存在,则将其添加到输出位集中。没有散列,没有分配,没有树平衡,几乎零页面错误,预取器友好,直接 O(1),占用空间最小,除了应该在缓存中的向量存储之外几乎没有间接性。
但如果这太过分了,您至少应该考虑使用哈希表而不是映射(所以使用 unordered_map 和 unordered_set)。但比集合更好的是向量(在这种情况下),因为您的键是字母,您可以将向量的大小预先设置为 26,然后从字符中减去“a”并将其用作索引和一个值0 或 1 表示存在。
此外,与上述无关,您的这段代码:
if (map2.count(s) == 0)
map2[s] = std::set<int>id;
else
map2[s].emplace(id);
写得更好:
map2[s].emplace(id);
注意:对于地图(和无序地图),如果不存在,operator[] 将创建一个默认构造元素,因此您不需要初始化集合的代码并增加开销。
【讨论】:
以上是关于在其他地图值中查找元素的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章