是否有O(1)方法将std :: map <keytype,value =“”>转换为std :: set <keytype> </keytype> </keytype,>

时间:2013-01-17 23:03:01

标签: c++ stdmap stdset

我想在std :: map&lt;&gt;的键上做一些交集操作。实例没有将密钥复制到std :: set&lt;&gt;预先。

它没有在API中记录,但是在O(1)时间内有任何方法从std :: map&lt;&gt;中提取密钥。并将它们放入std :: set&lt;&gt;?

3 个答案:

答案 0 :(得分:4)

创建一个迭代器适配器,该适配器首先返回地图并与set_intersection一起使用。

答案 1 :(得分:3)

首先不,没有O(1)操作从地图中获取一组键。构造集合必须是Omega(n)

但是,您可以直接在地图和其他范围内执行您想要的set_intersection,无论是什么。未经测试的代码:

template <typename InputIterator, typename Map, typename OutputIterator>
void map_set_intersection(InputIterator first, InputIterator last, const Map &m, OutputIterator o) {
    std::set_intersection(
        first, last, 
        m.begin(), m.end(), 
        o, 
        KeyCompare<typename Map::value_type, typename std::iterator_traits<InputIterator>::value_type>()
    );
}

所有魔法都在KeyCompare类型中:

template <typename MapValue, typename SetValue>
struct KeyCompare {
    bool operator()(const MapValue &lhs, const SetValue &rhs) {
        return lhs.first < rhs;
    }
    bool operator()(const SetValue &lhs, const MapValue &rhs) {
        return lhs < rhs.first;
    }
};

std::set_difference被定义为复制指定的 first 范围内的值,在这种情况下是迭代器定义的范围。它可以做到这一点,只要它可以将第一个范围中的值与第二个范围中的值按任意顺序进行比较(由于KeyCompare,它可以)。这两个范围不需要具有相同的类型,因此您不需要地图中的一组键。

如果您已经使用set_intersection的6参数形式,那么您需要更改KeyCompare,以便在从地图条目中取出密钥后,它会使用您的比较器代替<

如果您正在使用自定义比较器或重载operator< ,则迭代器范围的值类型与地图的值类型相同,那么这不会&# 39;工作。 KeyCompare不能再使用这些类型来确定提供参数的顺序,以及它应该从哪个提取first。我不认为这是一种非常常见的情况,但我也没有看到使用这种方法逃脱它。你需要Crazy Eddie的解决方案,适应地图迭代器。这相当于这个问题:Iterate keys in a C++ map

答案 2 :(得分:0)

您可以在地图上执行O(N)集合交集。请记住,当您遍历地图时,键是有序的,因此您可以使用非常类似于合并操作的算法...

您所做的只是在每个地图中维护一个迭代器,并递增其键最小的那个。如果键相等,则可以添加到dequelistvector(在这种情况下,您将增加两个迭代器)。只要其中一个迭代器到达其地图的末尾,就完成了。