【问题标题】: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 我只是不喜欢嵌套
  • 除此之外:你不需要ifmap2[s].emplace(id); 在这两种情况下都是正确的

标签: c++ algorithm data-structures


【解决方案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[] 将创建一个默认构造元素,因此您不需要初始化集合的代码并增加开销。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-10-14
          • 2011-08-18
          • 2012-03-21
          • 2010-09-28
          • 1970-01-01
          • 2014-12-05
          • 1970-01-01
          相关资源
          最近更新 更多