“小杜,咋闷闷不乐的?好像和今天的天气不搭调哦!——瞧!好大的太阳啊!”
“凯哥,原来是你啊,来的正好。我正在思考一个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;
}
//运行结果为:
“为什么结果是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 哦!”
“好的好的!”小杜频频点头!
“那就这样吧! 去晒太阳咯!”
………