c++ STL划分算法;partition()、partition_copy()、stable_partition()、partition_point()详解_迭代器

主要函数有:

  • partition():将满足某谓词的元素都放到前面。
  • stable_partition():将满足某谓词的元素都放到前面并维持原顺序。
  • partition():复制序列时将满足某谓词的元素都放到前面。
  • partition_point():获取分区点

partition函数模板的行为等效于:

template <class BidirectionalIterator, class UnaryPredicate>
  BidirectionalIterator partition (BidirectionalIterator first,
                                   BidirectionalIterator last, UnaryPredicate pred)
{
  while (first!=last) {
    while (pred(*first)) {
      ++first;
      if (first==last) return first;
    }
    do {
      --last;
      if (first==last) return first;
    } while (!pred(*last));
    swap (*first,*last);
    ++first;
  }
  return first;
}

first 和 last 都为正向迭代器,其组合 [first, last) 用于指定该函数的作用范围;pred 用于指定筛选规则。返回一个正向迭代器,其指向的是两部分数据的分界位置,更确切地说,指向的是第二组数据中的第 1 个元素。

功能: partition() 函数可根据用户自定义的筛选规则,重新排列指定区域内存储的数据,使其分为 2 组,第一组为符合筛选条件的数据,另一组为不符合筛选条件的数据。

例子:

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
int main(){
    int a[] = {1, 7, 2, 5, 3, 4, 8, 2, 3, 6};
    vector<int> v(a, a + 10);
    cout<< "原始数据: ";
    copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
    cout<< endl;
    
    cout<< "按<4条件划分(partition): ";
    partition(v.begin(), v.end(), bind2nd(less<int>(), 4));
    copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
    return 0;
}

c++ STL划分算法;partition()、partition_copy()、stable_partition()、partition_point()详解_算法_02

stable_partition函数模板原型为:

BidirectionalIterator stable_partition (BidirectionalIterator first,
                                        BidirectionalIterator last,
                                        UnaryPredicate pred);

参数与partition相同,只不过是稳定划分。当容器中两个元素同时满足条件或同时不满足条件时,原先在前面的元素当重新定位后仍在前面;如果一个元素满足条件另一个元素不满足条件时,则重新定位后元素的位置前后顺序不能确定。这通常使用内部临时缓冲区来实现。

例子:

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
int main(){
    int a[] = {1, 7, 2, 5, 3, 4, 8, 2, 3, 6};
    vector<int> v(a, a + 10);
    cout<< "原始数据: ";
    copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
    cout<< endl;
    
    cout<< "按<=4条件划分(stable_partition): ";
    stable_partition(v.begin(), v.end(), bind2nd(less_equal<int>(), 4));
    copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
    return 0;
}

c++ STL划分算法;partition()、partition_copy()、stable_partition()、partition_point()详解_算法_03

区分partition,stable_partition两个函数已知学生信息包含姓名和成绩两项,把学生集合中成绩小于75分的放在容器的前面。

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <string>
using namespace std;
struct Student{
    char name[20];
    int grade;
};
bool GradeCmp(Student& s){
    return s.grade < 75;
}
ostream& operator<<(ostream& os, const Student& s){
    os<<"(" << s.name << " " << s.grade << ")";
    return os;
}
int main(){
    Student s[] = {{"Anna", 79}, {"Mack", 70}, {"June", 68}, {"Lian", 78}, {"Jack", 65}};
    cout<< "学生原始数据: ";
    copy(s, s + 5, ostream_iterator<Student>(cout, " "));
    cout<< endl;
    
    vector<Student> v1(s, s + 5);
    cout<< "不稳定划分, 成绩<75(partition): " ;
    partition(v1.begin(), v1.end(),GradeCmp);
    copy(v1.begin(), v1.end(), ostream_iterator<Student>(cout, " "));
    cout << endl;
    
    vector<Student> v2(s, s + 5);
    cout<< "稳定划分, 成绩<75(stable_partition): " ;
    stable_partition(v2.begin(), v2.end(),GradeCmp);
    copy(v2.begin(), v2.end(), ostream_iterator<Student>(cout, " "));
    return 0;
}

c++ STL划分算法;partition()、partition_copy()、stable_partition()、partition_point()详解_STL库_04

上文已经详细介绍了 partition() 和 stable_partition() 函数的功能和用法。我们发现这 2 个函数在实现功能时,都直接修改了原序列中元素的存储位置。然而在某些场景中,我们需要类似 partition() 或者 stable_partition() 函数“分组”的功能,但并不想对原序列做任何修改。这种情况下,就可以考虑使用 partition_copy() 函数。

和 stable_partition() 一样,partition_copy() 函数也能按照某个筛选规则对指定区域内的数据进行“分组”,并且分组后不会改变各个元素的相对位置。更重要的是,partition_copy() 函数不会对原序列做修改,而是以复制的方式将序列中各个元组“分组”到其它的指定位置存储。

partition_copy函数模板的行为等效于:

template <class InputIterator, class OutputIterator1,
          class OutputIterator2, class UnaryPredicate pred>
  pair<OutputIterator1,OutputIterator2>
    partition_copy (InputIterator first, InputIterator last,
                    OutputIterator1 result_true, OutputIterator2 result_false,
                    UnaryPredicate pred)
{
  while (first!=last) {
    if (pred(*first)) {
      *result_true = *first;
      ++result_true;
    }
    else {
      *result_false = *first;
      ++result_false;
    }
    ++first;
  }
  return std::make_pair (result_true,result_false);
}
  • first、last:都为输入迭代器,其组合 [first, last) 用于指定该函数处理的数据区域;
  • result_true:为输出迭代器,其用于指定某个存储区域,以存储满足筛选条件的数据;
  • result_false:为输出迭代器,其用于指定某个存储区域,以存储满足筛选条件的数据;
  • pred:用于指定筛选规则,其本质就是接收一个具有 1 个参数且返回值类型为 bool 的函数。注意,该函数既可以是普通函数,还可以是一个函数对象。
  • 返回一个 pair 类型值,其包含 2 个迭代器,第一个迭代器指向的是 result_true 区域内最后一个元素之后的位置;第二个迭代器指向的是 result_false 区域内最后一个元素之后的位置

例子:

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
int main(){
    int a[] = {1, 7, 2, 5, 3, 4, 8, 2, 3, 6};
    vector<int> v(a, a + 10);
    cout<< "原始数据: ";
    copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
    cout<< endl;
    
    int b[10] = {0}, c[10] = {0};
    cout<< "按<4条件划分(partition): " << endl;
    pair<int *, int *> result = partition_copy(v.begin(), v.end(), b, c, bind2nd(less<int>(), 4));
    cout<< "满足筛选条件的数据: ";
    copy(b, result.first, ostream_iterator<int>(cout, " "));
    cout<< endl;
    cout<< "不满足筛选条件的数据: ";
    copy(c, result.second, ostream_iterator<int>(cout, " "));
    return 0;
}

c++ STL划分算法;partition()、partition_copy()、stable_partition()、partition_point()详解_迭代器_05

partition_point函数模板的行为等效于:

template <class ForwardIterator, class UnaryPredicate>
  ForwardIterator partition_point (ForwardIterator first, ForwardIterator last,
                                   UnaryPredicate pred)
{
  auto n = distance(first,last);
  while (n>0)
  {
    ForwardIterator it = first;
    auto step = n/2;
    std::advance (it,step);
    if (pred(*it)) { first=++it; n-=step+1; }
    else n=step;
  }
  return first;
}

partition()、stable_partition() 和 partition_copy() 这 3 个函数,它们的功能本质上都是根据某个筛选规则对指定范围内的数据进行分组(即符合条件的为一组,不符合条件的为另一组),并且反馈给我们两组数据之间的分界位置。而 partition_point()则是返回两组数据的分界点,即将迭代器返回到分区范围[first,last]中pred不为true的第一个元素,指示其分区点。

例子:

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
int main(){
    vector<int> v{1, 2, 3, 2, 3, 7, 5, 4, 8, 6};
    cout<< "原始数据: ";
    copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
    cout<< endl;
    vector<int>::iterator iter = partition_point(v.begin(), v.end(),  bind2nd(less<int>(), 4));
    cout<< "满足筛选条件的数据: ";
    copy(v.begin(), iter, ostream_iterator<int>(cout, " "));
    cout<< endl;
    cout<< "不满足筛选条件的数据: ";
    copy(iter, v.end(), ostream_iterator<int>(cout, " "));
    return 0;
}

c++ STL划分算法;partition()、partition_copy()、stable_partition()、partition_point()详解_STL库_06