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.

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

  1. STL算法

    STL算法部分主要由头文 件<algorithm>,<numeric>,<functional>组成.要使用 STL中的算法函数必须包含头文件<algorit ...

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

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

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

    前言 因为在前文的<STL算法剖析>中,源代码剖析许多,不方便学习,也不方便以后复习.这里把这些算法进行归类,对他们单独的源代码剖析进行解说.本文介绍的STL算法中的sort排序算法,SG ...

  4. C++11 STL算法简介

    STL(Standard Template Library),即标准模板库,是一个具有工业强度的,高效的C++程序库.它被容纳于C++标准程序库(C++ Standard Library)中,是ANS ...

  5. STL 算法介绍

    STL 算法介绍 算法概述 算法部分主要由头文件<algorithm>,<numeric>和<functional>组成.        <algorithm ...

  6. C++ 11 STL算法

    STL算法部分主要由头文件<algorithm>,<numeric>,<functional>组成.要使用 STL中的算法函数必须包含头文件<algorith ...

  7. STL 算法罗列 (转)

    非修改性序列操作(12个) 循环 for_each() 对序列中的每个元素执行某操作 查找 find() 在序列中找出某个值的第一次出现的位置 find_if() 在序列中找出符合某谓词的第一个元素 ...

  8. STL算法与树结构模板

    STL算法 STL 算法是一些模板函数,提供了相当多的有用算法和操作,从简单如for_each(遍历)到复杂如stable_sort(稳定排序),头文件是:#include <algorithm ...

  9. STL算法分类记忆

    STL算法主要是我们强大的标准库中以迭代器或数值或函数对象为参数预先定义好的一系列算法操作. 在STL算法分类中首先要提的就是两个普遍存在的后缀: _if _copy 其中这两个后缀的作用分别是:一. ...

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

    前言 在前面的博文中剖析了STL的数值算法.基本算法和set集合算法.本文剖析STL其它的算法,比如排序算法.合并算法.查找算法等等.在剖析的时候.会针对函数给出一些样例说明函数的使用.源代码出自SG ...

随机推荐

  1. SQL Server 2000 函数使用---CAST 和 CONVERT

    本文来自:http://www.cnblogs.com/xh831213/category/47654.html 将某种数据类型的表达式显式转换为另一种数据类型.CAST 和 CONVERT 提供相似 ...

  2. php 添加 redis 扩展模块

    由于PHP源码中并未有redis的文件,所以需要自己下载. 下载地址: http://pecl.php.net/get/redis-2.2.5.tgz [root@study package]# ta ...

  3. android——ObjectAnimator动画(一)

    直接贴上集中用法 package com.example.test; import com.example.test.views.CircleView; import android.animatio ...

  4. ng-class用法

    在angular中为我们提供了3种方案处理class: 1:scope变量绑定.这种方案不推荐,因为scope里最好处理业务逻辑,不去管渲染的事.2:字符串数组形式.3:对象key/value处理. ...

  5. uglifyjs入门接触

    一.背景 今天在看<锋利的jQuery>文时,突然看到Uglifyjs压缩工具,感觉值得一试(玩),所以网上稍微搜了一下资料,简单的运用了一下,发现入门非常简单,当然网上有很多在线压缩工具 ...

  6. 关于ASP.NET 中站点地图sitemap 的使用

    在ASP.NET  MVC 如此火热的时期,我竟然不适时宜的谈起ASP.NET ,恐怕会引来一阵嘲笑.最为无趣的是,讲解的竟然还是其中的一个控件.oh~~  my god!my out! ^_^ Si ...

  7. Linux下 输入 env 而得到的环境变量解读

    HOSTNAME=Master.Hadoop MAHOUT_HOME=/usr/hadoop/mahout-distribution-0.8 TERM=linux SHELL=/bin/bash HA ...

  8. react tab选项卡切换

    Tab选项卡切换是个很常见也很简单的小功能,用原生js和jq去写的话可能不到20行代码就搞定so easy.但是用react去实现就没那么容易了(是自己react比较菜).由于最近在重新学习react ...

  9. JVM内存区域划分Eden Space、Survivor Space、Tenured Gen,Perm Gen解释

    以下内容转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=29632145&id=4616836 jvm区域总体分两 ...

  10. 班上有学生若干名,已知每名学生的成绩(整数),求班上所有学生的平均成绩,保留到小数点后两位。同时输出该平均成绩整数部分四舍五入后的数值。 第一行有一个整数n(1<= n <= 100),表示学生的人数。其后n行每行有1个整数,表示每个学生的成绩,取值在int范围内。

    #include<iostream> #include<iomanip> using namespace std ; int main() { int n; while(cin ...