STL排序算法partial_sort_copy浅谈

“小杜,咋闷闷不乐的?好像和今天的天气不搭调哦!——瞧!好大的太阳啊!”

“凯哥,原来是你啊,来的正好。我正在思考一个STL上的一个问题,百思不得其解。”小杜很苦恼的说道。

“哦, STL上的? 刚好这段时间我也在看呢! 说来听听,一起探讨探讨。”

“关于partial_sort_copy() 函数,书中说 用来排序的,直至排序前n个元素,结果复制到目标区间中,并说: 如果目标区间[destBeg, destEnd ) 内的元素数量大于或等于源区间行为就相当于copy() 和 sort() 的组合。”

“对啊,是这样的啊。”

“关键是,现在如果目标空间比源空间要小呢 ?”小杜满是疑问的接着说:“不应该只对前n个元素进行排序,并将它们拷贝到[ destBeg, destEnd ) 吗 ?”

小杜将代码贴了出来

int main()
{
    deque<int> coll;
    vector<int> coll6(6),coll30(30);
    INSERT_ELEMENTS( coll,3,7);
    INSERT_ELEMENTS( coll,2,6);
    INSERT_ELEMENTS( coll,1,5);

    PRINT_ELEMENTS( coll,"coll :");
    PRINT_ELEMENTS( coll6,"coll6 :");
    cout<<"sizeof coll6 :"<<coll6.size()<<endl;
    vector<int>::iterator pos6;
    pos6= partial_sort_copy( coll.begin(), coll.end(),coll6.begin(), coll6.end() );
    copy( coll6.begin(), pos6, ostream_iterator<int>( cout,"coll6 : " ) );
   return 0;
}

 

//运行结果为:

clip_image002

“为什么结果是1 2 2 3 3 3 而不是 2 3 4 5 6 7呢?”

“这个问题其实与partial_sort_copy函数的实现有关系,该函数内部采heapsort算法实现。它能保证在任何情况下,算法复杂度为 n*log(n) ”

“让我们来看看partial_sort_copy函数的实现源码吧!”

  /**

  *  @brief Copy the smallestelements of a sequence using a predicate for

  *         comparison.

  *  @ingroup sorting_algorithms

  *  @param  first  An input iterator.

  *  @param  last   Another input iterator.

  *  @param  result_first  A random-access iterator.

  *  @param  result_last   Another random-access iterator.

  *  @param  comp   A comparison functor.

  *  @return   An iterator indicating the end of theresulting sequence.

   *

  *  Copies and sorts the smallest Nvalues from the range @p [first,last)

  *  to the range beginning at @presult_first, where the number of

  *  elements to be copied, @p N, isthe smaller of @p (last-first) and

  *  @p (result_last-result_first).

  *  After the sort if @p i and @jare iterators in the range

  *  @p[result_first,result_first+N) such that @i precedes @j then

  *  @p comp(*j,*i) is false.

  *  The value returned is @presult_first+N.

  */

template<typename _InputIterator, typename _RandomAccessIterator,typename _Compare>

   _RandomAccessIterator

   partial_sort_copy(_InputIterator __first, _InputIterator __last,

                    _RandomAccessIterator __result_first,

                    _RandomAccessIterator __result_last,

                    _Compare __comp)

    {

     typedef typename iterator_traits<_InputIterator>::value_type

       _InputValueType;

     typedef typenameiterator_traits<_RandomAccessIterator>::value_type

       _OutputValueType;

     typedef typename iterator_traits<_RandomAccessIterator>::difference_type

       _DistanceType;

 

     // concept requirements

     __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)

     __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<

                              _RandomAccessIterator>)

     __glibcxx_function_requires(_ConvertibleConcept<_InputValueType,

                              _OutputValueType>)

     __glibcxx_function_requires(_BinaryPredicateConcept<_Compare,

                              _InputValueType, _OutputValueType>)

     __glibcxx_function_requires(_BinaryPredicateConcept<_Compare,

                              _OutputValueType, _OutputValueType>)

     __glibcxx_requires_valid_range(__first, __last);

     __glibcxx_requires_valid_range(__result_first, __result_last);

 

     if (__result_first == __result_last)

       return__result_last;

     _RandomAccessIterator __result_real_last = __result_first;

     while(__first != __last && __result_real_last != __result_last)

       {

         *__result_real_last = *__first;

         ++__result_real_last;

         ++__first;

       }

      // 此处调用make_heap ,将一个区间转换成一个heap, 目的是要对这个区间进行堆操作

     std::make_heap(__result_first, __result_real_last, __comp);

     while (__first != __last)

       {

         if (__comp(*__first, *__result_first))

          // 调整该堆中的元素,主要是用__result_first保存该堆中最大的元素,并将*__first元素的值压入该堆中,

          //*__first 是源区间中未被目的区间引用的变量,替换掉__result_first所保存的最大值

           std::__adjust_heap(__result_first,_DistanceType(0),

                            _DistanceType(__result_real_last

                                        - __result_first),

                            _InputValueType(*__first),

                            __comp); 

         ++__first; //继续遍历

       }

     // 此处对heap中排序( 此时目标区间中的元素为 源区间中的最小值了,) 排序结束后,heap自动销毁

     std::sort_heap(__result_first, __result_real_last, __comp); 

     return __result_real_last;

    }

 

“根据源码,可以看到为什么是 1 2 2 3 3 3 了吧!”

“哦,原来是这样啊!”此时的小杜顿觉眼前豁然开朗!

 

“有时间可以研究研究 make_heap, __adjust_heap, 和 sort_heap 哦!”

“好的好的!”小杜频频点头!

“那就这样吧! 去晒太阳咯!”

………

posted on 2010-11-14 12:17  怕虫的瞌睡虫  阅读(1168)  评论(0编辑  收藏  举报

导航