简体   繁体   English

是否存在以以下方式对两个范围进行排序和划分的标准算法?

[英]Does a standard algorithm for sorting and partitioning two ranges in the following way exist?

I wonder whether a standard approach for the following algorithm exists. 我想知道是否存在用于以下算法的标准方法。 I want to sort and partition two ranges x and y . 我想对两个范围xy进行排序和分区。 Both x and y should be partitioned using a binary predicate that takes an element from x and y . xy都应使用从xy中获取元素的二进制谓词进行分区。 The signature of the function would be something along the lines of: 该函数的签名应类似于以下内容:

template<typename ForwardIt1, typename ForwardIt2, typename Compare, typename BinaryPredicate>
std::pair<ForwardIt1, ForwardIt2> sort_and_partition(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, ForwardIt2 last2, Compare comp, BinaryPredicate p);

Here comp is forwarded to std::sort . 在这里comp被转发到std::sort The binary predicate p is used for the partitioning. 二进制谓词p用于分区。 Then, for example: 然后,例如:

std::vector<T> x;
std::vector<T> y;

auto [xm, ym] = sort_and_partition(x.begin(), x.end(), y.begin(), y.end(), std::less<T>{}, std::equal_to<T>{});

This would result in four ranges: 这将导致四个范围:

  • x1: [x.begin(), xm) x1: [x.begin(), xm)
  • x2: [xm, x.end()) x2: [xm, x.end())
  • y1: [y.begin(), ym) y1: [y.begin(), ym)
  • y2: [ym, y.end()) y2: [ym, y.end())

Where both x1 and y1 are sorted and contain equivalent elements (according to the binary predicate p ). 其中x1y1都被排序并包含等效元素(根据二进制谓词p )。 Effectively x1 and y1 contain the sorted intersection for x and y in the example. 有效地x1y1包含示例中xy的排序交集。 x2 and y2 are sorted as well, and contain all elements unique to x and y respectively. x2y2也被排序,并且分别包含xy唯一的所有元素。

Am I missing an obvious approach to implement such an algorithm by combining existing algorithms in the STL? 我是否缺少通过组合STL中的现有算法来实现这种算法的明显方法? I am planning now to write a custom implementation for this but wanted to check here first before starting on the implementation. 我现在打算为此编写一个自定义实现,但是想先在这里进行检查,然后再开始实现。 What would be a good name for this algorithm? 这个算法的好名字是什么?

Update , I've implemented the following algorithm that satisfies my requirements. 更新 ,我实现了满足我的要求的以下算法。 The algorithm requires that the input ranges are sorted. 该算法要求对输入范围进行排序。

/// Takes two sorted input ranges, and partitions both ranges such that all
/// elements that occur in both ranges precede those elements that only occur in
/// one of the two ranges.
template<typename ForwardIt1, typename ForwardIt2, typename Compare>
std::pair<ForwardIt1, ForwardIt2> frc::binary_partition(
    ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, ForwardIt2 last2, Compare comp)
{
  auto equals = [&](const auto& x, const auto& y) { return !comp(x, y) && !comp(y, x); };

  // Invariant: first1 and last1 point to the first mismatch.
  std::tie(first1, first2) = std::mismatch(first1, last1, first2, last2, equals);

  while (first1 != last1 && first2 != last2)
  {
    // Iterators to the next matching elements.
    auto fm1{first1};
    auto fm2{first2};

    // Find next matching elements in both ranges.
    while (comp(*fm1, *fm2) || comp(*fm2, *fm1))
    {
      if (comp(*fm1, *fm2))
      {
        ++fm1;
      }
      else
      {
        ++fm2;
      }

      if (fm1 == last1 || fm2 == last2)
      {
        return std::pair(first1, first2);
      }
    }

    // Find the end of the matching subsequence.
    auto [lm1, lm2] = std::mismatch(fm1 + 1, last1, fm2 + 1, last2, equals);

    // In case matching elements are found, move the mismatching subrange behind
    // the matching subrange.
    first1 = std::rotate(first1, fm1, lm1);
    first2 = std::rotate(first2, fm2, lm2);
  }

  return std::pair(first1, first2);
}

No, and I can think of two reasons: 不,我可以想到两个原因:

  1. You're actually demanding two algorithms: std::sort and std::stable_partition (or std::partition and std::sort of both partitions of each range). 实际上,您需要两种算法: std::sortstd::stable_partition (或每个范围的两个分区的std::partitionstd::sort )。 You can compose that yourself. 您可以自己撰写。

  2. Algorithms implement their semantics in terms of iterators - that's where the extra part to make it work with two ranges should be implemented. 算法使用迭代器来实现其语义-在那儿应该实现使它与两个范围一起工作的额外部分。 In other words, if an algorithm's semantics can be defined with one input range, there won't be overloads for multiple ones. 换句话说,如果一种算法的语义可以在一个输入范围内定义,那么多个输入就不会有重载。

    You have to use a custom iterator, which will internally manipulate two iterators of distinct ranges (containers). 您必须使用自定义迭代器,该迭代器将在内部操纵两个不同范围的迭代器(容器)。 I think boost::zip_iterator is what you're looking for. 我认为boost::zip_iterator是您想要的。

There is no such function in STL as far as I know. 据我所知,STL中没有这样的功能。

Maybe what you could do is make use of the following functions provided by STL: 也许您可以做的是利用STL提供的以下功能:

  • sort x 排序x
  • sort y 排序y
  • use mismatch on x and y with a binary predicate 在x和y上使用不匹配的二元谓词

It returns a pair of iterators pointing to the first unmatched element of both sequences. 它返回指向两个序列中第一个不匹配元素的迭代器。

template <class InputIterator1, class InputIterator2, class BinaryPredicate>
  pair<InputIterator1, InputIterator2>
    mismatch (InputIterator1 first1, InputIterator1 last1,
              InputIterator2 first2, BinaryPredicate pred);

In the case where we can synthesize p from comp , this is roughly 在我们可以从comp合成p的情况下,这大概是

template<typename ForwardIt1, typename ForwardIt2, typename Compare>
std::pair<ForwardIt1, ForwardIt2> sort_and_partition(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, ForwardIt2 last2, Compare comp)
{
    // We don't strictly need copies of the two ranges, but it makes things easier. 
    // We do want them sorted, using an ordered set here gives that for free
    std::multiset<typename std::iterator_traits<ForwardIt1>::value_type, Compare> set1{ first1, last1, comp };
    std::multiset<typename std::iterator_traits<ForwardIt2>::value_type, Compare> set2{ first2, last2, comp };

    // Copy back into a partitioned [first1, last1)
    auto mid1 = std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(), first1, comp);
    std::set_difference(set1.begin(), set1.end(), set2.begin(), set2.end(), mid1, comp);

    // Copy back into a partitioned [first2, last2)
    auto mid2 = std::set_intersection(set2.begin(), set2.end(), set1.begin(), set1.end(), first2, comp);
    std::set_difference(set2.begin(), set2.end(), set1.begin(), set1.end(), mid2, comp);

    // And return our midpoints
    return { mid1, mid2 };
}

In the more general case, you will need to decide how many pairs of elements to compare in the partition step, as different choices will lead to different outcomes. 在更一般的情况下,您将需要决定在分区步骤中要比较多少对元素,因为不同的选择将导致不同的结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 是否有一种标准方法来比较 C++ 中的两个范围? - Is there a standard way to compare two ranges in C++? 是否有使用谓词比较两个范围的标准方法? - Is there a standard way to compare two ranges using a predicate? 在两个范围内按降序对向量进行排序 - Sorting a vector in descending order within two ranges 在标准(C ++ 14)中它表示以下两个声明是等效的吗? - Where in the Standard (C++14) does it say that the following two declarations are equivalent? 随机唯一整数的非标准排序算法 - Non-standard sorting algorithm for random unique integers 该算法可将两个范围的值相加并将其放入第三个范围 - algorithm to add values of two ranges and place them into a third one C ++是否有标准方法对两个std :: sets,vector等进行三态比较? - Does C++ have a standard way to do a tristate comparison of two std::sets, vectors, etc? 标准库是否有办法检查两个模板化类型的基本模板类型的相等性? - Does the standard library have a way to check the equality of two templated types' base template type? 如何在 C++ 中实现 K-Way 分区算法并收集 pivot 边界? - How to Implement K-Way Partitioning Algorithm in C++ and collect the pivot borders? 等效范围的STL算法 - STL algorithm for equivalent ranges
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM