STL中的排序算法一览[By ACM郭老师]

2023-11-17

这篇文章我很喜欢,是郭老师的新作!希望大家喜欢!
详细的从算法的效率方面来说明了排序算法!

STL中有多种排序算法,各有各的适用范围,下面听我一一道来:

I、完全排序
sort()
首先要隆重推出的当然是最最常用的sort了,sort有两种形式,第一种形式有两个迭代器参数,构成一个前开后闭的区间,按照元素的 less 关系排序;第二种形式多加一个指定排序准则的谓词。sort基本是最通用的排序函数,它使用快速排序算法,并且在递归过程中,当元素数目小于一个阈值(一般是16,我的试验是24)时,转成直接插入排序。伟大的数学家Knuth已经证明,在平均意义上,快速排序是最快的了;当然,最坏复杂性比较差。sort要求随机迭代器,因此对于很多编译器来说,对于前向迭代器(如list)使用sort是一个编译错误。(不过,在vc2005里面,这个错误信息实在很糟糕)

sort的基本使用方式如下:

  1. C++:   
  2.   
  3. #include <vector>   
  4. #include <algorithm>   
  5. #include <functional>   
  6. #include <cstdlib>   
  7.     
  8. using namespace std;   
  9.     
  10. void func1()   
  11. {   
  12.     vector<int> ar;   
  13.     //向数组里面插入一些随机数   
  14.     generate_n(back_inserter(ar), 100, rand);   
  15.     //按从小到大排序   
  16.     sort(ar.begin(), ar.end());   
  17. }    

经常有人问如何从大到小逆排序,这个其实有很多中方式实现,如下面的例子:
  1. C++:   
  2.   
  3. void func2()   
  4. {   
  5.     vector<int> ar;   
  6.     //向数组里面插入一些随机数   
  7.     generate_n(back_inserter(ar), 100, rand);   
  8.     
  9.     //方法1:使用函数作为谓词   
  10.     sort(ar.begin(), ar.end(), GreateThan);   
  11.     //方法2:使用仿函数作为谓词   
  12.     //注意下面两种方法都需要有个括号,实际上是要产生一个临时对象   
  13.     sort(ar.begin(), ar.end(), CompareInt());   
  14.     //方法3:使用预定义的Adapter, 定义在 <functional> 中   
  15.     sort(ar.begin(), ar.end(), greater<int>());   
  16.     //方法4:正常排序,然后翻转过来   
  17.     sort(ar.begin(), ar.end());   
  18.     reverse(ar.begin(), ar.end());   
  19.     //方法5:使用逆迭代器   
  20.     sort(ar.rbegin(), ar.rend());   
  21. }    
  22.   

最后一种方法是我比较欣赏的,可以不能直接对原生数组使用,也就是说,如果ar的定义是int ar[MAXN],上面其他的排序算法都可以简单的改成sort(ar, ar+MAXN, ...),但最后一个不行,要用另外一种比较丑陋的方式:

  1. C++:   
  2.   
  3. #include <iterator>   
  4. void func3(){   
  5.     int ax[5]={1,3,4,5,2};   
  6.     sort(reverse_iterator<int*>(ax+5), reverse_iterator<int*>(ax+0));   
  7. }    

stable_sort
sort优点一大堆,一个缺点就是它不是一种稳定的排序。什么是排序的稳定性,就是如果出现两个元素相等时,要求排序之后他们之间保持原来的次序(比如我们先按学号排序,然后按成绩排序,这时就希望成绩相同的还是按照学号的次序排)。很可惜,快速排序算法就不是稳定的,要追求这个,只好用stable_sort了。

在各种排序算法中,合并排序是稳定的,但一般的合并排序需要额外的O(N)的存储空间,而这个条件不是一定能够满足的(可能是比较奢侈的)。所以在stable_sort内部,首先判断是否有足够的额外空间(如vecotr中的cap-size()部分),有的话就使用普通合并函数,总的时间复杂性和快速排序一个数量级,都是O(N*logN)。如果没有额外空间,使用了一个merge_without_buffer的关键函数进行就地合并(如何实现是比较有技巧的,完全可以专门谈一谈),这个合并过程不需要额外的存储空间,但时间复杂度变成O(N*logN),这种情况下,总的stable_sort时间复杂度是O(N*logN*logN)。

总之,stable_sort稍微慢一点儿,但能够保证稳定,使用方法和sort一样。但很多时候可以不用这种方式和这个函数,比如上面的例子,完全可以在排序比较准则中写入成绩和学号两个条件就OK了
  1. C++:   
  2.   
  3. class CStudent   
  4. {   
  5. public:   
  6.     CStudent();   
  7.     //注意这个比较函数中的const   
  8.     bool operator<(const CStudent& rhs) const  
  9.     {   
  10.         if (m_score != rhs.m_score)   
  11.             return (m_score <rhs.m_score);   
  12.         return m_name <rhs.m_name;   
  13.     }   
  14. protected:   
  15.     std::string m_name;   
  16.     int m_score;   
  17. };   
  18.     
  19. void func4()   
  20. {   
  21.     vector<CStudent> arStu;   
  22.     sort(arStu.begin(), arStu.end());   
  23. }    

sort_heap
堆排序也是一种快速的排序算法,复杂度也是O(N*logN)。STL中有一些和堆相关的函数,能够构造堆,如果在构造好的堆上每次取出来根节点放在尾部,所有元素循环一遍,最后的结果也就有序了。这就是sort_heap了。它的使用要求区间前面已经构造成堆,如:
  1. C++:   
  2.   
  3. void func5()   
  4. {   
  5.     vector<int> ar;   
  6.     generate_n(back_inserter(ar), 100, rand);   
  7.     make_heap(ar.begin(), ar.end());   
  8.     sort_heap(ar.begin(), ar.end());   
  9. }    

list.sort
对于list容器,是不能直接使用sort的(包括stable_sort),从技术的角度来说是由于sort要求随机迭代器;从算法的角度来说,list这种链表结构就不适合用快速排序。因此,list容器内部实现了专门的sort算法,这个算法采用的是合并排序,应该是稳定的(不确定)。

其他
优先队列(priority_queue)每次弹出的都是max值。实际上就是heap的一个容器方式的包装。
关联式容器自身就必须是有序的(针对key),对其迭代时,key是递增的。
II、部分排序
这些部分排序功能能够完成一段数据(而不是所有)的排序,在适当的适合使用可以节省计算量。不过用的人不多。

partial_sort(), partial_sort_copy()
这两个函数能够将整个区间中给定数目的元素进行排序,也就是说,结果中只有最小的M个元素是有序的。你当然也可以使用sort,区别就在于效率。如果M显著地小于N,时间就比较短;当然M太小了也不好,那还不如挨个找最小值了。

partial_sort接受三个参数,分别是区间的头,中间和结尾。执行后,将前面M(M=中间-头)个元素有序地放在前面,后面的元素肯定是比前面的大,但他们内部的次序没有保证。partial_sort_copy的区别在于把结果放到另外指定的迭代器区间中:
  1. C++:   
  2.   
  3. void func6()   
  4. {   
  5.     int ar[12]={69,23,80,42,17,15,26,51,19,12,35,8};   
  6.     //只排序前7个数据   
  7.     partial_sort(ar, ar+7, ar+12);   
  8.     //结果是 8 12 15 17 19 23 26 80 69 51 42 35,后5个数据不定   
  9.     vector<int> res(7);   
  10.     //前7项排序后放入res   
  11.     partial_sort_copy(ar, ar+7, res.begin(), res.end(), greater<int>() );   
  12. }    

这两个函数的实现使用的是堆的方法,先将前M个元素构造成堆,然后挨个检查后面的元素,看看是否小于堆的最大值,是的话就彼此交换,然后重排堆;最后将前面已经是最小的M个元素构成的堆作一次sort_heap就可以了。算法的复杂度差不多是O(N*logM)

nth_element
这个函数只真正排序出一个元素来,就是第n个。函数有三个迭代器的输入(当然还可以加上一个谓词),执行完毕后,中间位置指向的元素保证和完全排序后这个位置的元素一致,前面区间的元素都小于(精确地说,是不大于)后面区间的元素。

熟悉快速排序的马上就能发现,这实际上是一个按位置划分的算法。STL的规范中要求此函数的平均复杂度是线性的,和快速排序一样,这种算法的最坏复杂度比较差。在一般的实现(如SGI)中,采用三种取1的方法寻找划分元素,最坏复杂度是O(N^N)。虽然理论上有一些算法可以保证最坏线性复杂度,但算法过于复杂,STL一般也不采用。

III、排序辅助功能
partition, stable_partition
merge, inplace_merge
IV、有序区间操作

这个准备单独写一篇
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STL中的排序算法一览[By ACM郭老师] 的相关文章

  • 将不同类型的对象与可比较的对象进行比较

    A java public class A implements Comparable private String id private String name public A String a String b id a name b
  • 如何在 LINQ 中执行 String.Replace?

    这是我正在尝试做的事情 但没有成功 我想打电话from x in list1 and join y in list2 where regex Match x Value Success 完成这些步骤后我需要打电话String Replace
  • JPA更新一对多关系列表

    我有一个 Question 实体 其中包含另一个名为 Alternatives 的实体的列表 如下所示 public class Question OneToMany fetch FetchType LAZY mappedBy questi
  • 以特定方式填充列表

    我需要填充一个包含 5 个位置的列表 new list 我收到 2 个列表 并且有一个默认值来填充新列表 现在开始解决问题 好的方式是 我从列表中接收 2 个值 从列表中接收 2 个值并添加默认值 A1 A2 DEFAULT B1 B2 但
  • 如何在 Python 中连接两个列表?

    这个问题的答案是社区努力 help privileges edit community wiki 编辑现有答案以改进这篇文章 目前不接受新的答案或互动 如何在 Python 中连接两个列表 Example listone 1 2 3 lis
  • Python-使用元组作为列表索引[重复]

    这个问题在这里已经有答案了 我有一个元组列表 tuples list 1 0 2 3 3 2 2 0 我想访问二维数组的元素a例如 使用其中一些元组 for i in range 3 print a tuples list i 应该输出的值
  • Python 3 中的递归搜索 JSON/DICT

    我在 Python 3 中实现了一些 API 这些 API 允许我根据班级代码接收有关学校的信息 但我想知道如何通过类代码获取信息 例子 我输入代码GF528S我希望程序告诉我班级 3C INF 地址 Address 1 Milan 如果可
  • 如何将列表转换为元组列表?

    我想转换 z z a z z a a z to z 2 a 1 z 2 a 2 z 1 我该怎么做 所以 我需要累积以前的值 它的计数器和元组列表 我已创建记录 record acc previous counter tuples 重新定义
  • git subtree pull -P 不管 总是合并冲突

    问题 即使我没有进行任何更改 每次尝试拉入子树时 我都会遇到合并冲突 我在做什么 In 子树仓库 Make some changes git commit am Changes made git push origin master In
  • 如何在 Haskell 中制作打勾游戏的图案?

    实现有 2 个参数的函数 ticktick 第一个参数是自然数元组 定义游戏场地的行数和列数 第二个列表包含由玩家 x 和玩家 o 轮流玩的坐标给出的井字游戏比赛的记录 打印游戏的实际状态 其中游戏区域将由字符 和 界定 空方块 以及字符
  • “Iterable 无法转换为 List” - `List` 不是 `Iterable` 的类型吗?

    我打电话给一个getElements返回的方法Iterable
  • 迭代列表的奇怪速度差异

    我创建了两个重复两个不同值的长列表 在第一个列表中 值交替出现 在第二个列表中 一个值出现在另一个值之前 a1 object object 10 6 a2 a1 2 a1 1 2 然后我迭代它们 不对它们执行任何操作 for in a1 p
  • 使用字符串中的变量名称访问变量值,R

    Intro 一个数据集有大量的age year变量 age 1990 age 1991 etc 我有一个字符串值数组length age years 表示这些变量 使得age years 1 回报 age 1990 etc Need 我想搜
  • Scala 中的随机列表[重复]

    这个问题在这里已经有答案了 我对 scala 中的随机播放列表有疑问 使用scala util Random 例如我有 val a cyan val b magenta val c yellow val d key val color Ra
  • C# List 内部结构

    将对象添加到集合 例如 List 时到底会发生什么 List
  • .join() 方法到底是做什么的?

    我对 Python 还很陌生 并且完全困惑 join 我读过的是连接字符串的首选方法 I tried strid repr 595 print array array c random sample string ascii letters
  • 在 R 中提取 data.frames 列表的名称以及 data.frame 中的值

    在下面的代码中 j是 data frames 的命名列表 我想知道是否有办法 a 提取变量的数值 即one short and one long 在 data frames 内并附加它们的相关名称 即 AAA or BBB or CCC 到
  • 删除 HashMap 中包含的列表项

    我有一个Hashmap
  • 按元组分隔符拆分列表

    我有清单 print L I WW am XX newbie YY ZZ You WW are XX cool YY ZZ 我想用分隔符将列表拆分为子列表 ZZ print new L I WW am XX newbie YY ZZ You
  • 使用 JS 合并具有相同值的相邻 HTML 表格单元格

    我已经为此苦苦挣扎了一段时间 我有一个根据一些 JSON 数据自动生成的表 该数据可能会有所不同 我想合并第一列中具有相同值的相邻单元格 例如此表中的 鱼 和 鸟 table tr td fish td td salmon td tr tr

随机推荐

  • Windows下在后台运行jar包

    为什么80 的码农都做不了架构师 gt gt gt 新建一个bat文件 输入 echo off start javaw jar xxx jar exit 执行这个批处理程序就可以在后台运行jar包了 转载于 https my oschina
  • FIddler之Fiddler移动端抓包

    前言 笔者今天的这篇文章呢 想使用通俗易懂的话语 让大家明白以下内容 什么是抓包哪些场景需要用到抓包Fiddler抓包的原理怎样使用Fiddler进行移动端抓包 一 抓包 包 Packet 是TCP IP协议通信传输中的数据单位 一般也称
  • Apache/Tomcat/JBOSS/Jetty/Nginx区别 与选择

    总结 Apache Tomcat JBOSS Nginx区别 1 Apache是Web服务器 Tomcat是应用 Java 服务器 Tomcat在中小型系统和并发访问用户不是很多的场合下被普遍使用 Apache支持静态页 Tomcat支持动
  • 千行代码bug率统计

    1 计算公式 千行代码bug率 bug数 代码行数 1000 2 bug率标准 CMMI级别中做出了相关的指标规定 千行代码缺陷率 bug率 CMM1级 11 95 CMM2级 5 52 CMM3级 2 39 CMM4级 0 92 CMM5
  • JWT(Json Web Token)的原理、渗透与防御

    关于JWT kid安全部分后期整理完毕再进行更新 2023 05 16 JWT的原理 渗透与防御 目录 JWT的原理 渗透与防御 含义 原理 JWT的起源 传统session认证问题 token与session区别 JWT的结构与内容 JW
  • CVPR 2020-Object Detection

    目录 2D目标检测 视频目标检测 2D目标检测 Large Scale Object Detection in the Wild From Imbalanced Multi Labels Rethinking Classification
  • 芯片手册中的英文的表示含义

    芯片手册中的英文的表示含义 在读芯片的数据手册的时候 会有一些英文表示不知道是什么含义 现在整理了一些在下面 1 ppm 在一些电压芯片数据手册里 有一个描述基准性能的直流参数 称为温度漂移 也称温度系数 或简称TC Temperature
  • 机器学习之朴素贝叶斯: sklearn.naive_bayes

    朴素贝叶斯 sklearn naive bayes 1 贝叶斯原理 2 朴素贝叶斯 3 朴素贝叶斯模型 3 1 多项式模型MultinomialNB 3 2 高斯模型GaussianNB 3 3 伯努利模型BernoulliNB 4 skl
  • Python爬虫之爬取CSDN人工智能栏目的文章

    在进行正式开始爬虫之旅前 我们要认识几个Python库 urllib2 Python标准库 该库中提供了一系列针对url的操作方法 re Python标准库 提供了一系列针对字符串匹配的方法 BeautifulSoup4 最主要的功能是从网
  • 【推荐算法】双塔模型介绍

    双塔模型的结构不仅在推荐领域的召回和粗排环节中被广泛采用 而且在其它领域 如文档检索 问答系统等都有它的应用场景 我们常说的双塔模型的结构 并不是一个固定不变的网络 而是一种模型构造思路 即把模型分成用户侧模型和物品侧模型两部分 然后用互操
  • LaTeX公式、图片编辑中的常见问题(字体、对齐、编号等)

    类似博文 https blog csdn net u011698800 article details 109456028 输入保留符号 LaTeX中有许多字符都有特殊的意义 LaTeX中的保留字符有 这些在正文中都不能直接呈现 反斜杠用
  • C++数据结构X篇_02_线性表基本概念(线性表是零或者多个数据元素的有限序列;有顺序,有限,类型必须相同;线性表是具有相同类型n个数据元素的有限序列(a0,a1,...an)ai是表项,n是表长度)

    接上篇C 数据结构X篇 01 数据结构的基本概念 本篇将会学习线性表的基本概念 线性表的基本概念 1 线性表的基本概念 1 1 线性表的基本概念 1 1 1 线性表的特性 1 2 线性表的数学定义 1 2 1 线性表的性质 1 3 线性表的
  • 好家伙谷歌翻译又不能用了(有效解决方法)

    今天打开idea想翻译单词发现谷歌翻译又又又挂了 为什么挂掉 可能是那个ip节点太多人用了 我也不懂我就是一个小白 不bb了说一下解决方法 一 手动Ping可以连接的ip 这里我使用的是 https ping chinaz com 然后我们
  • 适合有编程基础的人看的《韩顺平零基础30天学java》笔记(374~397)

    写在最前边 研究生一枚 为后端实习和未来工作打基础 无意间发现韩顺平老师的课程 细心细致 讲课和吴恩达老师一样 都是保姆式讲解 各种基础知识都会补充 爱了 韩顺平老师课程地址 https www bilibili com video BV1
  • 眼底图像血管增强与分割--(2)Gabor滤波算法原理及实现

    在http blog csdn net piaoxuezhong article details 78213672中介绍了匹配滤波算法用于血管分割 本篇继续介绍血管分割的另一种方法 Gabor滤波算法 具体可以参见论文 Retinal Ve
  • 大律法(OTSU) ——图像数据二值化

    二值化的目的 是确定一个像素值 以像素为分界 将图像划分为前景和背景 前景的像素值取相同值 背景的像素也取相同值 从而将前景和背景的差异 在图像中最大化 或者说可以突出前景或者背景信息 二值化可以有效的降低噪声 并且可以一定程度的增强目标特
  • 数据结构刷题:第十六天(基础)

    目录 一 颜色分类 1 单指针 复杂度分析 2 双指针 复杂度分析 二 合并区间 1 排序 思路 看题解 一 颜色分类 75 颜色分类 力扣 LeetCode https leetcode cn problems sort colors p
  • HDU-2000

    题目本身不难 但是对于初学者 难的是数据的读入 方法一 使用getchar 去除每一行的空格符 include
  • git撤回push代码方法 分支受保护 不受保护时 详解

    git撤回push代码方法 分支受保护 不受保护时 详解 1 分支受保护时用revert 1 先说结果 如果分支受保护 那么就不能reset方法来撤回 原因后面说 那么需要通过revert来撤回 2 可以的方法 git revert能够生成
  • STL中的排序算法一览[By ACM郭老师]

    这篇文章我很喜欢 是郭老师的新作 希望大家喜欢 详细的从算法的效率方面来说明了排序算法 STL中有多种排序算法 各有各的适用范围 下面听我一一道来 I 完全排序 sort 首先要隆重推出的当然是最最常用的sort了 sort有两种形式 第一