7.8. Выполнение для последовательностей операций над множествами
Проблема
Имеются последовательности, которые требуется реорганизовать с помощью операций над множествами, таких как объединение (union), различие (difference) или пересечение (intersection).
Решение
Для этой цели используйте специальные функции стандартной библиотеки.
set_union
,
set_difference
и
set_intersection
.
Каждая из них выполняет соответствующую операцию над множеством и помещает результат в выходной диапазон. Их использование показано в примере 7.8.
Пример 7.8. Использование операций над множествами
#include <iostream>
#include <algorithm>
#include <string>
#include <set>
#include <iterator>
#include "utils.h" // Для printContainer: см. 7.10
Операции с множествами в стандартной библиотеке выглядят и работают сходным образом. Каждая принимает два диапазона, выполняет свою операцию с ними и помешает результаты в выходной итератор. Вы должны убедиться, что для выходной последовательности имеется достаточно места, или использовать
inserter
или
back_inserter
(как использовать
back_inserter
,
рассказывается в рецепте 7.5).
Объявление
set_union
выглядит вот так.
Out set_union(In first1, In last1, In first2, In last2, Out result);
Объявления
set_difference
,
set_intersection
и
set_symmetric_difference
выглядят точно так же.
Чтобы использовать эти функции, сделайте так, как показано в примере 7.8. Например, чтобы найти пересечение двух множеств, вызовите
, который принимает контейнер и итератор и возвращает выходной итератор, который при записи в него значения вызывает для первого аргумента
inserter
метод
insert
. При его использовании для последовательного контейнера он вставляет значения перед
iterator
, переданным в качестве второго аргумента. При его использовании для ассоциативного контейнера, как это делается в показанном выше фрагменте кода, этот итератор игнорируется, и элементы вставляются в соответствии с критерием сортировки контейнера.
set
— это удобный пример для наших целей, но операции над множествами работают для любых последовательностей, а не только для
set
. Например, операции над множествами можно выполнить для
list
:
list<string> lst1, lst2, lst3;
// Заполняем их данными
lst1.sort; // Элементы должны быть отсортированы
lst2.sort;
set_symmetric_difference(lst1 begin, lst1.end,
lst2.begin, lst2.end, back_inserter(lst3));
Однако так как
list
хранит данные в неотсортированном виде, его вначале требуется отсортировать иначе результаты операций над множествами будут неверными. Также обратите внимание, что в этом примере вместо
inserter
используется
back_inserter
.
back_inserter
работает аналогично
inserter
, за исключением того, что для добавления элементов в контейнер он использует
push_back
. Вы не обязаны действовать точно так же. Например, можно изменить размер выходного контейнера так, чтобы он стал достаточно большим
lst3.resize(lst1.size + lst2.size),
set_symmetric_difference(lst1.begin, lst1.end,
lst2.begin, lst2.end, lst3.begin)
;
Если выходная последовательность будет достаточно большой, то можно просто передать итератор, указывающий на первый элемент последовательности, используя
begin
.
Если вы не знаете, что такое
set_symmetric_difference
, я вам расскажу. Это объединение разностей двух множеств, определенных в прямом и обратном порядке. Это значит, что если а и b — это множества, то симметричная разность — это а - b b - а. Другими словами, симметричная разность — это множество всех элементов, которые присутствуют в одном из множеств, но отсутствуют в другом.