• 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 哦!”

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

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

    ………

  • 相关阅读:
    python执行线程方法
    Python 多线程教程:并发与并行
    python中遍历文件的3个方法
    docker-compose编写(英文)
    使用Docker构建redis集群--最靠谱的版本
    iptables四个表与五个链间的处理关系
    Docker相关文档
    HTTP 之 Content-Type
    Python之VSCode
    自定义分页
  • 原文地址:https://www.cnblogs.com/bylikai/p/1876913.html
Copyright © 2020-2023  润新知