【STL】算法 — partial_sort

partial_sort接受一个middle迭代器。使序列中的middle-first个最小元素以递增顺序排序,置于[first, middle)内。以下是測试代码:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main()
{
    int a[] = {10,9,8,7,6,5,4,3,2,1,0};
    vector<int> vec(a, a+11);
    vector<int>::iterator b = vec.begin();
    vector<int>::iterator e = vec.end();

    partial_sort(b, b+6, e);     // 前6个最小元素排序
    while (b != e)
        cout << *(b++) << ‘ ‘;
    return 0;
}

运行结果:

从结果能够看出,前6个最小元素放在了前6个位置上,而剩下的元素则放于容器后面未排序。

实现partial_sort的思想是:对原始容器内区间为[first, middle)的元素运行make_heap()操作构造一个最大堆。然后拿[middle, last)中的每一个元素和first进行比較。first内的元素为堆内的最大值。假设小于该最大值。则互换元素位置。并对[first, middle)内的元素进行调整,使其保持最大堆序。比較完之后在对[first, middle)内的元素做一次对排序sort_heap()操作。使其按增序排列。注意,堆序和增序是不同的。

以下分析STL的源代码。

partial_sort有两个版本号,一个默认以小于作为比較规则。出来的顺序为递增排列。

还有一个能够传入一个仿函数,即自己定义比較规则。这里仅仅分析前者。

template <class RandomAccessIterator>
inline void partial_sort(RandomAccessIterator first,
                         RandomAccessIterator middle,
                         RandomAccessIterator last) {
  __partial_sort(first, middle, last, value_type(first));
}

进入__partial_sort函数:

template <class RandomAccessIterator, class T>
void __partial_sort(RandomAccessIterator first, RandomAccessIterator middle,
                    RandomAccessIterator last, T*) {
  make_heap(first, middle); // [first, middle)区间构造一个heap
  for (RandomAccessIterator i = middle; i < last; ++i)
    if (*i < *first)        // 当前元素比堆中最大的元素小
      __pop_heap(first, middle, i, T(*i), distance_type(first));  // first值放i中,i的原值融入heap并调整
  sort_heap(first, middle);
}

此函数和上面的文字描写叙述基本同样。有一点小的差别在于当*i < *first时,代码中没有互换i所指元素和first所指元素。

究竟怎么做的?来看看__pop_heap函数:

template <class RandomAccessIterator, class T, class Distance>
inline void __pop_heap(RandomAccessIterator first, RandomAccessIterator last,
                       RandomAccessIterator result, T value, Distance*) {
  *result = *first; // 弹出元素放vector尾端
  __adjust_heap(first, Distance(0), Distance(last - first), value);
}

此函数把first中的元素放在了result,也就是i位置上。成功地把最大值挤出了[first, middle)区间。但此时first位置形成了一个空洞,即索引值Distance(0),所以须要调整heap,这由__adjust_heap函数负责。

调整大致过程是找出最大元素放入first。然后把value保存的值插入到堆的适当位置,在这里value即为T(*i),即把i所指元素融入到了[first,
middle)区间。

由此可见。__adjust_heap的复用性还是非常高的。

再回到__partial_sort函数。for循环就是反复上面的“挤出”和“融入”操作直到容器末尾。当跳出for循环时,区间[first, middle)中已经存放有容器的前middle-first个最小元素了。

最后运行sort_heap(),由堆序变为增序排列:

template <class RandomAccessIterator>
void sort_heap(RandomAccessIterator first, RandomAccessIterator last) {
  while (last - first > 1) pop_heap(first, last--);
}

弹出堆的最大值并放入尾部,然后缩小堆的范围,循环运行弹出操作直至堆仅仅剩下最后一个元素。这样就能够达到排序效果了。注意,此函数仅仅能用于堆上。

若要对整个普通容器施行堆排序操作,能够借partial_sort接口,仅仅需把middle參数改为last就可以:

partial_sort(first, last, last);

这样的方法用到了STL的高速排序身上。感觉越来越有意思了。

个人认为这个局部排序还是蛮重要的,至少是它的排序思想非常好。要不然STL也不会使用它了。

參考:

《STL源代码剖析》 P386.

原文地址:https://www.cnblogs.com/xfgnongmin/p/10620536.html

时间: 2024-07-28 16:23:56

【STL】算法 — partial_sort的相关文章

STL算法 — sort

能使用STL的sort系列算法的前提是容器的迭代器必须为随机迭代器.所以,vector和deque天然适用.STL的sort算法采用了一些策略,在不同情况下采用不同的排序算法,以达到各种算法优势互补的效果.基本的原则是:数据量大时采用快速排序,数据量小时采用插入排序(这是对快排常用的一种优化策略),递归层次过深改用堆排序. 首先是插入排序.它的平均和最坏时间复杂度都为O(N2),量级小于千,那么插入排序还是一个不错的选择.SGI STL的插入排序默认以增序排列,另外还可以传入一个仿函数作为比较规

算法 — partial_sort

partial_sort接受一个middle迭代器,使序列中的middle-first个最小元素以递增顺序排序,置于[first, middle)内.下面是测试代码: #include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { int a[] = {10,9,8,7,6,5,4,3,2,1,0}; vector<int> vec(a,

【C/C++学院】0830-兰不达表达式/STL算法-操作数据

兰不达表达式 #include<iostream> #include<vector> #include<algorithm>//算法 lambda表达式,不仅仅适用与array ,也适用于vector void main1() { std::vector<int> myvector; myvector.push_back(11); myvector.push_back(22); myvector.push_back(33); myvector.push_ba

STL源代码分析——STL算法sort排序算法

前言 因为在前文的<STL算法剖析>中,源代码剖析许多,不方便学习,也不方便以后复习.这里把这些算法进行归类,对他们单独的源代码剖析进行解说.本文介绍的STL算法中的sort排序算法,SGI STL中的排序算法不是简单的高速排序,而是交叉利用各种排序:堆排序.插入排序和高速排序:这样做的目的是提高效率.针对数据量比較大的採用高速排序,数据量比較小的能够採用堆排序或插入排序. 本文介绍了有关排序的算法random_shuffle.partition.stable_partition.sort.s

STL算法之排序算法

STL排序算法通常复杂度坏于线性,且必须要random-access Iterators. 所以,forward_list, list, associative and unordered contains 不提供随机访问迭代器,这些容器不能用排序算法. 但是,forward_list,list提供了成员函数sort,associative contains 自动排序,unordered contains不能排序. 通常,排序元素一次要比保持元素有序要更快.STL提供了不同的排序算法,根据需求选

STL 算法[转 ]

STL 算法 STL算法概述 简介: STL算法部分主要由头文 件<algorithm>,<numeric>,<functional>组成.要使用 STL中的算法函数必须包含头文件<algorithm>,对于数值算法须包 含<numeric>,<functional>中则定义了一些模板类,用来声明函数对象 注意: 编译器无法检测出所传递的迭代器是一个无效形式的迭代器,当然也无法给出算法函数错误的提示,因为迭代器并不是真实的类别,它只是

STL源码剖析——STL算法stl_algo.h

前言 在前面的博文中剖析了STL的数值算法.基本算法和set集合算法,本文剖析STL其他的算法,例如排序算法.合并算法.查找算法等等.在剖析的时候,会针对函数给出一些例子说明函数的使用.源码出自SGI STL中的<stl_algo.h>文件.注:本文的源码非常多,可能后续博文会对这些算法进行归类分析. STL算法剖析 #ifndef __SGI_STL_INTERNAL_ALGO_H #define __SGI_STL_INTERNAL_ALGO_H #include <stl_heap

STL源码剖析——STL算法之sort排序算法

前言 由于在前文的<STL算法剖析>中,源码剖析非常多,不方便学习,也不方便以后复习,这里把这些算法进行归类,对他们单独的源码剖析进行讲解.本文介绍的STL算法中的sort排序算法,SGI STL中的排序算法不是简单的快速排序,而是交叉利用各种排序:堆排序.插入排序和快速排序:这样做的目的是提高效率,针对数据量比较大的采用快速排序,数据量比较小的可以采用堆排序或插入排序.注意:STL的sort排序算法的迭代器必须是随机访问迭代器. sort排序算法剖析 // Return a random n

【STL源码学习】STL算法学习之四

排序算法是STL算法中相当常用的一个类别,包括部分排序和全部排序算法,依据效率和应用场景进行选择. 明细: sort 函数原型: template <class RandomAccessIterator> void sort (RandomAccessIterator first, RandomAccessIterator last); template <class RandomAccessIterator, class Compare> void sort (RandomAcc

STL 算法

STL 算法(本文转自:http://www.cnblogs.com/kzloser/archive/2012/11/02/2751424.html) 阅读目录如下: STL算法概述查找算法堆算法关系算法集合算法排列组合算法排序和通用算法删除和替换算法生成和变异算法算数算法 STL算法概述 简介: STL算法部分主要由头文件<algorithm>,<numeric>,<functional>组成.要使用 STL中的算法函数必须包含头文件<algorithm>