【问题标题】:What's the difference between set<pair> and map in C++?C++ 中的 set<pair> 和 map 有什么区别?
【发布时间】:2011-03-15 23:33:53
【问题描述】:

有两种方法可以在 C++ STL 中轻松创建键值属性:映射和对集。例如,我可能有

map<key_class,value_class>

set<pair<key_class,value_class> >

在算法复杂度和编码风格方面,这些用法有什么区别?

【问题讨论】:

  • 也许你是想问多地图而不是地图?
  • @RobKennedy:也许你的意思是多集和多图......
  • 当时没有,@Einpoklum。我的意思是,为了使用映射来保存与set&lt;pair&gt; 可以保存的所有相同的值,您需要映射为multimap。我没有考虑的是要保存multimap 可以保存的所有值,您又需要将集合设置为multiset&lt;pair&gt;。感谢您提请我注意。

标签: c++ data-structures stl map set


【解决方案1】:

它们在语义上是不同的。考虑:

#include <set>
#include <map>
#include <utility>
#include <iostream>

using namespace std;

int main() {
  pair<int, int> p1(1, 1);
  pair<int, int> p2(1, 2);
  set< pair<int, int> > s;
  s.insert(p1);
  s.insert(p2);
  map<int, int> m;
  m.insert(p1);
  m.insert(p2);
  cout << "Set size = " << s.size() << endl;
  cout << "Map size = " << m.size() << endl;
}

http://ideone.com/cZ8Vjr

输出:

设置大小 = 2
地图大小 = 1

【讨论】:

  • 发布结果输出 + 1 行见解会更加完整。不过 +1。
  • map 不允许重复键
  • 如果您用此代码替换集合声明,那么集合也不允许重复键:auto less_than = [](pair&lt;int, int&gt; p1, pair&lt;int, int&gt; p2) { return p1.first &lt; p2.first; }; set&lt; pair&lt;int, int&gt;, decltype(less_than) &gt; s(less_than);
  • Map 按键值排序,不允许重复键。但是如果只有值不同,则允许 Set 重复键。
  • 但是如果一个集合使用一个自定义的比较器函数,它只比较该对的第一个字段,它们是等价的(除了 const-ness)对吧?
【解决方案2】:

集合元素在集合中时不能修改。 setiteratorconst_iterator 是等价的。因此,对于set&lt;pair&lt;key_class,value_class&gt; &gt;,您不能就地修改value_class。您必须从集合中删除旧值并添加新值。但是,如果value_class 是一个指针,这并不妨碍您修改它指向的对象。

使用map&lt;key_class,value_class&gt;,您可以就地修改value_class,假设您有一个对地图的非常量引用。

【讨论】:

    【解决方案3】:

    map&lt;key_class,value_class&gt; 将按 key_class 排序,不允许 key_class 重复。
    set&lt;pair&lt;key_class,value_class&gt; &gt; 将按 key_class 排序,然后在 key_class 实例相等时按 value_class 排序,并允许 key_class 有多个值

    【讨论】:

      【解决方案4】:

      基本区别在于,对于集合,键是对,而对于映射,键是 key_class - 这使得通过 key_class 查找内容,这是您想要对映射执行的操作,对于集合来说很困难。

      两者通常使用相同的数据结构(通常是红黑平衡二叉树)实现,因此两者的复杂度应该相同。

      【讨论】:

      • 我可以使用 lower_bound 和 upper_bound 来查找集合的值。
      【解决方案5】:

      std::map 充当关联数据结构。换句话说,它允许您使用其关联的键来查询和修改值。

      std::set&lt;pair&lt;K,V&gt; &gt; 可以这样工作,但是您必须使用键和更多代码为查询编写额外的代码来修改值(即删除旧对并插入另一个具有相同键和不同的值)。您还必须确保具有相同键的值不超过两个(您猜对了,更多代码)。

      换句话说,您可以尝试将std::set 硬塞到像std::map 一样工作,但没有理由这样做。

      【讨论】:

      • 确实,我只会使用 std::map :p
      • 我使用 set 而不是 multimap 来有效地查找/删除键值。使用 multimap 我需要两个迭代器,内部迭代器是 O(m)。
      【解决方案6】:

      要了解算法的复杂性,您首先需要了解实现。

      std::map 是使用 RB-tree 实现的,而 hash_map 是使用链表数组实现的。 std::map 为插入/删除/搜索操作提供 O(log(n)),hash_map 是 O(1) 是最好的情况,最坏的情况是 o(n),具体取决于哈希冲突。

      【讨论】:

      • hash_map 是什么?不是将mapset 进行比较,而不是将maphash_map 进行比较?
      • by hash_map,@sach 指的是 unordered_map
      【解决方案7】:

      可视化 Philipp 在逐步执行代码后提到的语义差异,注意 map 键是如何是 const int 以及 p2 是如何没有插入到 m 中的:

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-24
        • 1970-01-01
        • 2014-03-15
        • 2011-01-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多