如何计算两个多重集的就地设置差异?

时间:2013-04-18 09:34:15

标签: c++

假设我有两个多重集。我想删除第一个多集中出现在第二个多集中的所有元素,遵循每个多集中出现的每个元素的次数。例如,如果多重集a包含1五次,多重b两次,则在我计算a -= b时,只应移除两个1个实例来自a

以下是一些实现此目的的代码:

 multiset<int> a;
 multiset<int> b;

 // remove all items that occur in b from a, respecting count ("a -= b")
 for (multiset<int>::iterator i = b.begin(); i != b.end(); i++) {
    if (a.count(*i) < 1) {
       // error 
    }
    // a.erase(*i) would remove ALL elements equal to *i from a, but we 
    // only want to remove one.  a.find(*i) gives an iterator to the first
    // occurrence of *i in a.
    a.erase(a.find(*i));
  }

当然有更好/更惯用的方法吗?

4 个答案:

答案 0 :(得分:10)

虽然std::set_difference要求您将元素放入新的集合中,但您仍然可以通过元素从原始集合移动到新集合中然后交换两者来优化它(好吧,对于int移动不是必要的,但这样算法保持灵活和通用)。

std::multiset<int> c;
std::set_difference(std::make_move_iterator(a.begin()), 
                    std::make_move_iterator(a.end()), 
                    b.begin(), b.end(), 
                    std::inserter(c, c.begin()));
a.swap(c);

不是完全就地,但几乎并且仍然非常惯用,而且复杂性是线性的(因为std::insert_iterator将始终为std::multiset::insert提供正确的提示。)< / p>

答案 1 :(得分:3)

请参阅std::set_difference

它也适用于多重集合。

来自最新的草案n3485 25.4.5.4 [set.di ff erence]

Remarks: If [first1,last1) contains m elements that are equivalent to each other and
[first2, last2) contains n elements that are equivalent to them, the last max(m−n,0)
elements from [first1, last1) shall be copied to the output range.

答案 2 :(得分:2)

由于容器是有序的,你可以一次迭代这两个容器,跳过只在一个容器中的值;类似的东西:

for (auto i = a.begin, j = b.begin(); i != a.end() && j != b.end();) {
    if (*i < *j) {
        ++i;
    } else if (*j < *i) {
        ++j;
    } else {
        i = a.erase(i);
        ++j;
    }
}

这具有线性复杂性,避免了对countfind的对数时间调用。

或者,如果您不介意将要保留的元素移动到新地图中,则可以使用std::set_difference。这可能不是线性时间,因为每个元素都需要插入到输出映射中。

更新:在进一步调查时,std::set_difference似乎是线性的,因为在给出合适的提示时插入必须是线性的,insert_iterator将提供正确的提示。如果你不介意构建一个新的multiset的额外内存使用,那么这可能被认为是更惯用的。

答案 3 :(得分:2)

使用std::set_difference,但它会创建一个新的第三个集合:

std::multiset<int> v1{1, 2, 5, 5, 5, 9};
std::multiset<int> v2{2, 5, 7};
std::multiset<int> diff;

std::set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(),
                    std::inserter(diff, diff.begin()));

输出

1 5 5 9