推广标准::p艺术到multi_partition

Generalizing std::partition to multi_partition

本文关键字:multi partition 标准 艺术      更新时间:2023-10-16

就像std::p artition根据一元谓词对容器进行分区一样,multi_partition是根据一元谓词对容器进行分区...pred 的顺序与 UnaryPredicates 中列出的顺序相同...,而 false 元素的顺序与 UnaryPredicates 的顺序相同...以及在容器的末尾,并返回所有分区点的列表。 但是我用这个辅助函数没有得到正确的结果:

template <typename ForwardIterator, typename UnaryPredicate, typename... UnaryPredicates>
std::list<ForwardIterator> multi_partition_helper (std::list<ForwardIterator>& partition_points, 
    ForwardIterator first, ForwardIterator last, UnaryPredicate pred, UnaryPredicates... rest) {
    while (true) {
        while ((first != last) && pred(*first))
            ++first;
        if (first == last--) break;
        while ((first != last) && !pred(*last))
            --last;
        if (first == last) break;
        std::iter_swap (first++, last);
    }
    partition_points.push_back (first);
    multi_partition_helper (partition_points, first, last, rest...);
}
template <typename ForwardIterator, typename UnaryPredicate, typename... UnaryPredicates>
std::list<ForwardIterator> multi_partition_helper (std::list<ForwardIterator>&, ForwardIterator, ForwardIterator) {
// End of recursion.
}

我的做法是不是错了?

一个简单的实现是

template <typename BidirIt, typename... Predicates>
void trivial_mul_part( BidirIt first, BidirIt last, Predicates... preds )
{
    std::sort( first, last,
      [=] (decltype(*first) const& lhs, decltype(*first) const& rhs)
      {
          return std::make_tuple(preds(lhs)...) > std::make_tuple(preds(rhs)...);
      } );
}

并可用作参考算法。
真正的算法可以根据std::partition本身递归实现。这个想法是用 n 个谓词调用 std::partition,将迭代器获取到 n+1范围的开头,然后使用此迭代器作为第一个迭代器,将第 n+1谓词作为谓词进行下一次调用。

template <typename BidirIt, typename OutputIterator>
void multi_partition( BidirIt first, BidirIt last, OutputIterator out ) {}
template <typename BidirIt, typename OutputIterator,
          typename Pred, typename... Predicates>
void multi_partition( BidirIt first, BidirIt last,  OutputIterator out,
                      Pred pred, Predicates... preds )
{
    auto iter = std::partition(first, last, pred);
    *out++ = iter;
    multi_partition<BidirIt>(iter, last, out, preds...);
}

作为实际算法,其使用方式如下:

int arr[] {0, 1, 0, 1, 0, 2, 1, 2, 2};
std::vector<int*> iters;
multi_partition(std::begin(arr), std::end(arr), std::back_inserter(iters),
                 [] (int i) {return i == 2;},
                 [] (int i) {return i == 1;});
for (auto i : arr)
    std::cout << i << ", ";
std::cout << 'n';
for (auto it : iters)
    std::cout << "Split at " << it - arr << 'n';

演示。