STL之partial_sort

本文深入解析了部分排序算法partial_sort及其辅助函数的功能与实现机制,包括两种版本:默认使用小于运算符进行比较的版本和使用自定义比较函数的版本。此外,还介绍了partial_sort_copy函数,它将排序后的元素复制到另一个容器中。
// partial_sort, partial_sort_copy, and auxiliary functions.
//重新安排序列[first,last),使序列前半部分middle-first个最小元素以递增顺序排序,并将其置于[first,middle)
//其余last-middle个元素不指定任何排序,并将其置于[middle,last)
//注意:迭代器middle是在[first,last)范围之内

/*
函数功能:Rearranges the elements in the range [first,last), 
in such a way that the elements before middle are the smallest elements in the entire range 
and are sorted in ascending order, while the remaining elements are left without any specific order.

函数原型:
default (1)	版本一 operator< 
	template <class RandomAccessIterator>
	void partial_sort (RandomAccessIterator first, RandomAccessIterator middle,
                     RandomAccessIterator last);
custom (2) 版本二 comp	
	template <class RandomAccessIterator, class Compare>
	void partial_sort (RandomAccessIterator first, RandomAccessIterator middle,
                     RandomAccessIterator last, Compare comp);
*/

template <class _RandomAccessIter, class _Tp>
void __partial_sort(_RandomAccessIter __first, _RandomAccessIter __middle,
                    _RandomAccessIter __last, _Tp*) {
		//利用heap的知识,在SGI STL中,是采用最大堆
		//将[first,middle)区间的元素创建成最大堆
		//再根据最大堆的性质,一个一个弹出堆,并将其保存,即堆排序
  make_heap(__first, __middle);//创建最大堆,定义与<stl_heap.h>文件
  //以下是在区间中[first,last)找出middle-first个最小元素
  //这里的是将后半部分[middle,last)的元素依次与最大堆的根节点元素(即堆的最大元素)比较
  //若小于堆的最大元素,则与堆的最大元素交换,并调整堆,使其依次成为最大堆
  //若不小于堆的最大元素,则不作任何操作
  for (_RandomAccessIter __i = __middle; __i < __last; ++__i)
    if (*__i < *__first) 
      __pop_heap(__first, __middle, __i, _Tp(*__i),
                 __DISTANCE_TYPE(__first));
  sort_heap(__first, __middle);//对最大堆进行堆排序
}
//版本一
template <class _RandomAccessIter>
inline void partial_sort(_RandomAccessIter __first,
                         _RandomAccessIter __middle,
                         _RandomAccessIter __last) {
  __STL_REQUIRES(_RandomAccessIter, _Mutable_RandomAccessIterator);
  __STL_REQUIRES(typename iterator_traits<_RandomAccessIter>::value_type,
                 _LessThanComparable);
  __partial_sort(__first, __middle, __last, __VALUE_TYPE(__first));
}

template <class _RandomAccessIter, class _Tp, class _Compare>
void __partial_sort(_RandomAccessIter __first, _RandomAccessIter __middle,
                    _RandomAccessIter __last, _Tp*, _Compare __comp) {
  make_heap(__first, __middle, __comp);
  for (_RandomAccessIter __i = __middle; __i < __last; ++__i)
    if (__comp(*__i, *__first))
      __pop_heap(__first, __middle, __i, _Tp(*__i), __comp,
                 __DISTANCE_TYPE(__first));
  sort_heap(__first, __middle, __comp);
}
//版本二
template <class _RandomAccessIter, class _Compare>
inline void partial_sort(_RandomAccessIter __first,
                         _RandomAccessIter __middle,
                         _RandomAccessIter __last, _Compare __comp) {
  __STL_REQUIRES(_RandomAccessIter, _Mutable_RandomAccessIterator);
  __STL_BINARY_FUNCTION_CHECK(_Compare, bool, 
      typename iterator_traits<_RandomAccessIter>::value_type,
      typename iterator_traits<_RandomAccessIter>::value_type);
  __partial_sort(__first, __middle, __last, __VALUE_TYPE(__first), __comp);
}
//partial_sort_copy与partial_sort的实现机制是相同,只是partial_sort_copy将元素排序后放在以result起始的容器中
template <class _InputIter, class _RandomAccessIter, class _Distance,
          class _Tp>
_RandomAccessIter __partial_sort_copy(_InputIter __first,
                                      _InputIter __last,
                                      _RandomAccessIter __result_first,
                                      _RandomAccessIter __result_last, 
                                      _Distance*, _Tp*) {
  if (__result_first == __result_last) return __result_last;
  _RandomAccessIter __result_real_last = __result_first;
  while(__first != __last && __result_real_last != __result_last) {
    *__result_real_last = *__first;
    ++__result_real_last;
    ++__first;
  }
  make_heap(__result_first, __result_real_last);
  while (__first != __last) {
    if (*__first < *__result_first) 
      __adjust_heap(__result_first, _Distance(0),
                    _Distance(__result_real_last - __result_first),
                    _Tp(*__first));
    ++__first;
  }
  sort_heap(__result_first, __result_real_last);
  return __result_real_last;
}

template <class _InputIter, class _RandomAccessIter>
inline _RandomAccessIter
partial_sort_copy(_InputIter __first, _InputIter __last,
                  _RandomAccessIter __result_first,
                  _RandomAccessIter __result_last) {
  __STL_REQUIRES(_InputIter, _InputIterator);
  __STL_REQUIRES(_RandomAccessIter, _Mutable_RandomAccessIterator);
  __STL_CONVERTIBLE(typename iterator_traits<_InputIter>::value_type,
                    typename iterator_traits<_RandomAccessIter>::value_type);
  __STL_REQUIRES(typename iterator_traits<_RandomAccessIter>::value_type,
                 _LessThanComparable);
  __STL_REQUIRES(typename iterator_traits<_InputIter>::value_type,
                 _LessThanComparable);
  return __partial_sort_copy(__first, __last, __result_first, __result_last, 
                             __DISTANCE_TYPE(__result_first),
                             __VALUE_TYPE(__first));
}

template <class _InputIter, class _RandomAccessIter, class _Compare,
          class _Distance, class _Tp>
_RandomAccessIter __partial_sort_copy(_InputIter __first,
                                         _InputIter __last,
                                         _RandomAccessIter __result_first,
                                         _RandomAccessIter __result_last,
                                         _Compare __comp, _Distance*, _Tp*) {
  if (__result_first == __result_last) return __result_last;
  _RandomAccessIter __result_real_last = __result_first;
  while(__first != __last && __result_real_last != __result_last) {
    *__result_real_last = *__first;
    ++__result_real_last;
    ++__first;
  }
  make_heap(__result_first, __result_real_last, __comp);
  while (__first != __last) {
    if (__comp(*__first, *__result_first))
      __adjust_heap(__result_first, _Distance(0),
                    _Distance(__result_real_last - __result_first),
                    _Tp(*__first),
                    __comp);
    ++__first;
  }
  sort_heap(__result_first, __result_real_last, __comp);
  return __result_real_last;
}

template <class _InputIter, class _RandomAccessIter, class _Compare>
inline _RandomAccessIter
partial_sort_copy(_InputIter __first, _InputIter __last,
                  _RandomAccessIter __result_first,
                  _RandomAccessIter __result_last, _Compare __comp) {
  __STL_REQUIRES(_InputIter, _InputIterator);
  __STL_REQUIRES(_RandomAccessIter, _Mutable_RandomAccessIterator);
  __STL_CONVERTIBLE(typename iterator_traits<_InputIter>::value_type,
                    typename iterator_traits<_RandomAccessIter>::value_type);
  __STL_BINARY_FUNCTION_CHECK(_Compare, bool,
     typename iterator_traits<_RandomAccessIter>::value_type,
     typename iterator_traits<_RandomAccessIter>::value_type);  
  return __partial_sort_copy(__first, __last, __result_first, __result_last,
                             __comp,
                             __DISTANCE_TYPE(__result_first),
                             __VALUE_TYPE(__first));
}

### C++ `std::partial_sort` 函数详解 #### 定义与功能 `std::partial_sort` 是 C++ STL 中的一个算法,用于部分排序容器中的元素。它会将指定范围内的前 N 个小的元素按升序排列到目标位置上,而其余未涉及的部分则保持原样或无特定顺序[^1]。 该函数的主要特点是效率较高,因为它不需要对整个序列进行全面排序即可完成任务。其时间复杂度通常优于完全排序的操作(如 `std::sort`),尤其是在只需要获取少量有序数据的情况下非常有用。 --- #### 基本语法 以下是 `std::partial_sort` 的通用声明形式: ```cpp template< class RandomIt > void partial_sort( RandomIt first, RandomIt middle, RandomIt last ); template< class RandomIt, class Compare > void partial_sort( RandomIt first, RandomIt middle, RandomIt last, Compare comp ); ``` - **参数解释** - `first`: 输入区间的起始迭代器。 - `middle`: 部分排序结束的位置(即要保留多少个最小/最大值)。 - `last`: 输入区间的终止迭代器。 - `comp`(可选): 自定义比较函数对象,默认为 `<` 运算符。 对于 C++20 及更高版本,还支持带执行策略 (`ExecutionPolicy`) 的重载版本[^4]。 --- #### 使用示例 ##### 示例 1:字符串部分排序 下面是一个简单的例子,展示如何通过 `std::partial_sort` 对字符串的一部分进行排序。 ```cpp #include <iostream> #include <algorithm> #include <string> int main() { std::string s = "987654321"; // 将前五个字符从小到大排序 std::partial_sort(s.begin(), s.begin() + 5, s.end()); std::cout << s << std::endl; // 输出: 123459876 } ``` 此代码片段展示了如何利用 `std::partial_sort` 来仅改变原始字符串的一小部分内容,并不影响其他区域[^2]。 --- ##### 示例 2:自定义结构体排序 当处理更复杂的类型时,可以提供一个 lambda 表达式作为比较器来实现定制化行为。 ```cpp #include <iostream> #include <algorithm> #include <vector> struct SData { int m_nData; double m_dData; SData(int nData, double dData) : m_nData(nData), m_dData(dData) {} }; int main() { std::vector<SData> v; for (int i = 9; i > 0; --i) { v.emplace_back(i, static_cast<double>(i)); } // 按照成员变量 m_nData 升序排列前五项 std::partial_sort(v.begin(), v.begin() + 5, v.end(), [](const SData& a, const SData& b) -> bool { return a.m_nData < b.m_nData; }); for (const auto& item : v) { std::cout << item.m_nData << ' '; } std::cout << '\n'; // 输出: 1 2 3 4 5 9 8 7 6 } ``` 上述程序演示了针对用户定义的数据类型的灵活应用方式。 --- #### 注意事项 虽然 `std::partial_sort` 提供了一种高效的方法来进行局部排序,但在某些场景下可能并非最佳选择。如果仅仅是为了提取最前面若干个极值,则考虑采用堆队列技术——比如借助于 `std::nth_element` 或者优先级队列可能会更加合适[^4]。 另外需要注意的是,在调用过程中传入的有效区间 `[first,middle)` 和 `[middle,last)` 应满足基本条件约束;否则可能导致未定义的行为发生。 --- ### 总结 综上所述,`std::partial_sort` 不失为一种强大工具,尤其适用于那些只需关注整体集合中某一部分的情况之下。然而实际开发当中还需权衡性能需求以及具体应用场景等因素再做决定。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值