Ответ 1
Он не работает на месте, но если предположить, что ни один диапазон не содержит дубликатов заранее, std::set_union
найдет тот же результат, что и слияние, за которым следует уникальный.
Я попытался найти алгоритм, который бы сделал то, что std::inplace_merge
а затем std::unique
. Кажется более эффективным сделать это за 1 проход, чем в 2.
Не удалось найти его в стандартной библиотеке или ооглинге.
Он не работает на месте, но если предположить, что ни один диапазон не содержит дубликатов заранее, std::set_union
найдет тот же результат, что и слияние, за которым следует уникальный.
В разделе алгоритмов отсутствует много интересных алгоритмов. Оригинальное представление STL было неполным из взгляда Степанова, и некоторые алгоритмы были даже удалены. Предложение Александра Степанова и Мэн Ли не включает в себя алгоритм inplace_merge_unique()
или любые его варианты.
Одна из потенциальных причин, почему нет такого алгоритма, заключается в том, что не ясно, какой из элементов следует отбросить: поскольку сравнение является лишь строгим слабым порядком, выбор элемента имеет значение. Один из подходов к реализации inplace_merge_unique()
-
std::remove_if()
для удаления любого элемента, который является дубликатом из второго диапазона.inplace_merge()
для выполнения фактического слияния.Предикат std::remove_if()
будет отслеживать текущую позицию в первой части последовательности, которая должна быть объединена. Код ниже не протестирован, но что-то вроде этого должно работать:
template <typename BiDirIt, typename Comp>
BiDirIt inplace_merge_unique(BiDirIt begin, BiDirIt middle, BiDirIt end, Comp comp) {
using reference = typename std::iterator_traits<BiDirIt>::reference;
BiDirIt result = std::remove_if(middle, end, [=](reference other) mutable -> bool {
begin = std::find_if(begin, middle, [=](reference arg)->bool {
return !comp(arg, other);
});
return begin != middle && !comp(other, *begin);
});
std::inplace_merge(begin, middle, result, comp);
return result;
}