标准库partition相关函数

使用一个东西,不明白它的道理,不高明
——侯捷老师

1. partition()函数

将输入序列转换划分成两个部分,函数返回值是第二个部分的第一个元素的迭代器。

1.1. 函数声明

template <class ForwardIterator, class UnaryPredicate>
            ForwardIterator partition (ForwardIterator first,
                                       ForwardIterator last, 
                                       UnaryPredicate pred);

1.2. 等价操作实现

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)
                } while (!pred(*last));
                swap(*first, *last);
                ++first;
            }
            return first;
        }

1.3. 源码探究

partition()->std::__partition()->iter_swap()

partition()函数:

template<typename _ForwardIterator, typename _Predicate>
    inline _ForwardIterator
    partition(_ForwardIterator __first, _ForwardIterator __last,
          _Predicate   __pred)
    {
      // concept requirements
      __glibcxx_function_requires(_Mutable_ForwardIteratorConcept<
                  _ForwardIterator>)
      __glibcxx_function_requires(_UnaryPredicateConcept<_Predicate,
        typename iterator_traits<_ForwardIterator>::value_type>)
      __glibcxx_requires_valid_range(__first, __last);

      return std::__partition(__first, __last, __pred,
                  std::__iterator_category(__first));
    }

std::__partition()函数:

template<typename _BidirectionalIterator, typename _Predicate>
    _BidirectionalIterator
    __partition(_BidirectionalIterator __first, _BidirectionalIterator __last,
        _Predicate __pred, bidirectional_iterator_tag)
    {
      while (true)
    {
      while (true)
        if (__first == __last)
          return __first;
        else if (__pred(*__first))
          ++__first;
        else
          break;
      --__last;
      while (true)
        if (__first == __last)
          return __first;
        else if (!bool(__pred(*__last)))
          --__last;
        else
          break;
      std::iter_swap(__first, __last);
      ++__first;
    }
    }

iter_swap()函数:

template<typename _FIter1, typename _FIter2>
    void 
    iter_swap(_FIter1, _FIter2);

1.4. 示例程式

void test_partition() {
        vector<int> vec;
        for (int i = 1; i <= 10; i++) {
            vec.push_back(i);
        }
        
        vector<int>::iterator bound;
        bound = std::partition(vec.begin(), vec.end(), [](int i) {
            return i % 2 == 1;
        });
        
        cout << "Odd elements: ";
        for (auto it = vec.begin(); it != bound; it++) {
            cout << *it << " ";
        }
        cout << endl;
        
        cout << "Even elements: ";
        for (auto it = bound; it != vec.end(); it++) {
            cout << *it << " ";
        }
        cout << endl;
    }

1.5 输出结果

image.png

参考链接:http://www.cplusplus.com/reference/algorithm/partition/

2. partition_copy()函数

将[first,last)区间里满足/不满足pred的分别拷贝到对应的区间

2.1 函数声明

template<class InputIterator, class OutputIterator1,
         class OutputIterator2, class UnaryPredicate pred>
            pair<OutputIterator1, OutputIterator2>
                partition_copy(InputItertor first, InputIterator last,
                               OutputIterator1 result_true, OutputIterator2 result_false,
                               UnaryPredicate pred);

2.2 等价操作实现

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);
}

2.3 源码探究

template<typename _InputIterator, typename _OutputIterator1,
       typename _OutputIterator2, typename _Predicate>
    pair<_OutputIterator1, _OutputIterator2>
    partition_copy(_InputIterator __first, _InputIterator __last,
           _OutputIterator1 __out_true, _OutputIterator2 __out_false,
           _Predicate __pred)
    {
      // concept requirements
      __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
      __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator1,
        typename iterator_traits<_InputIterator>::value_type>)
      __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator2,
        typename iterator_traits<_InputIterator>::value_type>)
      __glibcxx_function_requires(_UnaryPredicateConcept<_Predicate,
        typename iterator_traits<_InputIterator>::value_type>)
      __glibcxx_requires_valid_range(__first, __last);
      
      for (; __first != __last; ++__first)
    if (__pred(*__first))
      {
        *__out_true = *__first;
        ++__out_true;
      }
    else
      {
        *__out_false = *__first;
        ++__out_false;
      }

      return pair<_OutputIterator1, _OutputIterator2>(__out_true, __out_false);
    }

2.4 示例程式

void test_partition_copy() {
        vector<int> foo {1,2,3,4,5,6,7,8,9};
        vector<int> odd, even;
        
        int n = std::count_if(foo.begin(), foo.end(), [](int i) {
            return i % 2 == 1;
        });
        
        odd.resize(n);
        even.resize(foo.size() - n);
        
        std::partition_copy(foo.begin(), foo.end(), odd.begin(), even.begin(), [](int i) {
            return i % 2 == 1;
        });
        
        cout << "odd: ";
        for (auto& x : odd) {
            cout << x << " ";
        }
        cout <<endl;
        
        cout << "even: ";
        for (auto& x : even) {
            cout << x << " ";
        }
        cout << endl;
    }

2.5 输出结果

image.png

2.6 参考链接

http://www.cplusplus.com/reference/algorithm/partition_copy/

3. partition_point()函数

功能:返回指向第一个不是属于第一类序列的元素的迭代器

3.1 函数声明

template<class ForwardIterator, class UnaryPredicate>
        ForwardIterator partition_point(ForwardIterator first, ForwardIteartor last,
                                        UnaryPredicate pred);

3.2 等价操作实现

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;
}

3.3 源码探究

template<typename _ForwardIterator, typename _Predicate>
    _ForwardIterator
    partition_point(_ForwardIterator __first, _ForwardIterator __last,
            _Predicate __pred)
    {
      // concept requirements
      __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>)
      __glibcxx_function_requires(_UnaryPredicateConcept<_Predicate,
          typename iterator_traits<_ForwardIterator>::value_type>)

      // A specific debug-mode test will be necessary...
      __glibcxx_requires_valid_range(__first, __last);

      typedef typename iterator_traits<_ForwardIterator>::difference_type
    _DistanceType;

      _DistanceType __len = std::distance(__first, __last);
      _DistanceType __half;
      _ForwardIterator __middle;

      while (__len > 0)
    {
      __half = __len >> 1;
      __middle = __first;
      std::advance(__middle, __half);
      if (__pred(*__middle))
        {
          __first = __middle;
          ++__first;
          __len = __len - __half - 1;
        }
      else
        __len = __half;
    }
      return __first;
    }

3.4 示例程式

void test_partition_point() {
        vector<int> vec = {1,2,3,4,5,6,7,8,9};
        std::vector<int> odd;
        std::partition(vec.begin(), vec.end(), [](int i) {
            return i % 2 == 1;
        });
        
        auto it = std::partition_point(vec.begin(), vec.end(), [](int i) {
            return i % 2 == 1;
        });
        
        odd.assign(vec.begin(), it);
        
        cout << "odd contains: ";
        for (auto& x : odd) {
            cout << x << " ";
        }
        cout << endl;
    }

输出结果:


image.png

为何不是有序的?

3.5 参考链接

http://www.cplusplus.com/reference/algorithm/partition_point/

4. is_partitioned()函数

4.1 函数声明

template<class InputIterator, class UnaryPredicate>
        bool is_partitioned(InputIterator first, InputIterator last, UnaryPredicate pred)

4.2 等价操作实现

template <class InputIterator, class UnaryPredicate>
  bool is_partitioned (InputIterator first, InputIterator last, UnaryPredicate pred)
{
  while (first!=last && pred(*first)) {
    ++first;
  }
  while (first!=last) {
    if (pred(*first)) return false;
    ++first;
  }
  return true;
}

4.3 源码探究

template<typename _InputIterator, typename _Predicate>
    inline bool
    is_partitioned(_InputIterator __first, _InputIterator __last,
           _Predicate __pred)
    {
      __first = std::find_if_not(__first, __last, __pred);
      return std::none_of(__first, __last, __pred);
    }

none_of()函数

template<typename _InputIterator, typename _Predicate>
    inline bool
    none_of(_InputIterator __first, _InputIterator __last, _Predicate __pred)
    { return __last == _GLIBCXX_STD_A::find_if(__first, __last, __pred); }

find_if()函数

template<typename _InputIterator, typename _Predicate>
    inline _InputIterator
    find_if(_InputIterator __first, _InputIterator __last,
        _Predicate __pred)
    {
      // concept requirements
      __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
      __glibcxx_function_requires(_UnaryPredicateConcept<_Predicate,
          typename iterator_traits<_InputIterator>::value_type>)
      __glibcxx_requires_valid_range(__first, __last);

      return std::__find_if(__first, __last,
                __gnu_cxx::__ops::__pred_iter(__pred));
    }

4.4 示例程式

/**
    template<class InputIterator, class UnaryPredicate>
        bool is_partitioned(InputIterator first, InputIterator last, UnaryPredicate pred);
    */
    
    bool IsOdd (int i) { return (i%2)==1; }
    void test_is_partitioned() {
        std::array<int,7> foo {1,2,3,4,5,6,7};

        // print contents:
        std::cout << "foo:"; for (int& x:foo) std::cout << ' ' << x;
        if ( std::is_partitioned(foo.begin(),foo.end(),IsOdd) )
            std::cout << " (partitioned)\n";
        else
            std::cout << " (not partitioned)\n";
        
        // partition array:
        std::partition (foo.begin(),foo.end(),IsOdd);
        
        // print contents again:
        std::cout << "foo:"; for (int& x:foo) std::cout << ' ' << x;
        if ( std::is_partitioned(foo.begin(),foo.end(),IsOdd) )
            std::cout << " (partitioned)\n";
        else
            std::cout << " (not partitioned)\n";
    }

输出结果:


image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354