我想知道是否有一种算法可以合并满足谓词的集合中的元素 类似于以下代码:
struct Element
{
int size;
constexpr static int maxSize = 150;
enum Type { Mergeable, notMergeable } type;
};
auto predicate = [](const Element& el1, const Element& el2)
{
//Done by the algorithm
if(&el1 == &el2) // An element should not merge with itself obviously
return false;
if(el1.size == 0 || el2.size == 0) //element is marked for deletion
return false;
//User predicate:
bool isBelowMaxSize = el1.size + el2.size < Element::maxSize;
bool isMergeable = el1.type == Element::Type::Mergeable && el2.type == Element::Type::Mergeable;
return isBelowMaxSize && isMergeable;
}
//User merge function
auto merge = [](Element& el1, Element& el2)
{
el1 += el2;
//Done by the algorithm
el2.size = 0; //Marks for deletion
}
int main()
std::vector<Element> els;
//Let's assume els contains elements
for(auto& el1 : els)
for(auto& el2 : els)
if(predicate(el1, el2))
merge(el1, el2)
//Merged elements are now removed
}
我以为我可以对范围做同样的事情:
namespace rv = ranges::views;
auto result = rv::cartesian_product(els, els) | rv::filter(predicate) | rv::for_each(merge);
但是我担心它无法正常工作,因为它可能会尝试合并已经合并的元素。
那么,有没有一种干净的方法?
答案 0 :(得分:2)
您可以通过首先将所有Element::Type::Mergeable
和size < Element::maxSize
的{{1}}项过滤到一个单独的容器中(这是 O(n)),然后按大小排序( O(n log n))。
有了分类的候选容器,您可以轻松地从两端进行遍历,直到迭代器在中间相遇为止。组合最大和最小元素将在线性时间内给出所有允许的合并。
答案 1 :(得分:0)
感谢@ Useless,@ Ted Lyngmo和@Caleth的帮助,这是我的答案
//Expects a range sorted in descending order
template<class It, class Predicate, class Sum>
[[nodiscard]] static It merge_if(It first, It last, Predicate predicate, Sum sum)
{
assert(first != last);
last--;
while (first != last)
{
while (predicate(*first, *last))
{
*first = sum(*first, *last);
last--;
}
first++;
}
first++;
return first; //One past the end
}
template<class It, class Predicate>
[[nodiscard]] static It merge_if(It first, It last, Predicate predicate)
{
using Type = std::remove_cv_t<std::remove_reference_t<decltype(*first)>>;
auto plus = [](const Type &first, const Type &second) { return first + second; };
return merge_if(first, last, predicate, plus);
}
my GitLab上有一些测试用例