排序算法概览
排序算法概览
四分之一以上的CPU时间都用于执行同一类型的计算:按照某种约定的次序,将给定的一组元素顺序排列,比如将n个整数按通常的大小次序排成一个非降序列。这类操作统称排序(sorting)。——D. Knuth
可见,掌握好常用的排序算法在学习计算机科学学科以及软件工程学科中非常重要的意义。排序算法中又分为很多种不同的算法,冒泡排序、快速排序、归并排序等等。本文就常见的排序给出做一个总览性的分类,从较高一点的层次观察排序算法的整体情况,而具体某个算法的细节请参看其他篇的文章:-D。
===
排序算法的分类
关于排序算法,其实有不同的分类方式。从大的方向分为两类:
- 内排序:
待排序列完全存放在内存中所进行的排序过程,适合不太大的元素序列
- 外排序:
指能够处理极大量数据的排序算法。通常来说,外排序处理的数据不能一次装入内存,只能放在读写较慢的外存储器(通常是硬盘)上。外排序通常采用的是一种“排序-归并”的策略。在排序阶段,先读入能放在内存中的数据量,将其排序输出到一个临时文件,依此进行,将待排序数据组织为多个有序的临时文件。尔后在归并阶段将这些临时文件组合为一个大的有序文件,也即排序结果。
本文以下部分注重于对内排序算法的分类
常见的内排序分类标准:
- 是否是稳定的算法
- 时间复杂度
- 运行时空间开销
稳定性(Stability)
当某个内排序算法被称为是稳定的,是指该稳定排序算法会让原本有相等键值的记录维持相对次序。也就是说在一个待排序的元素列表中,有两个元素A和B,他们代表的值相等,且A的位置在B前面。在排序完成后的有序列表中,A也将会是在B之前。
下面的表列举常见的一些排序算法是否是稳定的
稳定的 | 不稳定的 |
---|---|
冒泡排序 | 选择排序 |
鸡尾酒排序(双向冒泡排序) | 希尔排序 |
插入排序 | 堆排序 |
归并排序 | 快速排序 |
。。。 | 。。。 |
时间复杂度(Computational complexity)
时间复杂度可以衡量一个算法的性能。用大O记号标记。理想状态下O(n)复杂度的算法是最好的,可惜实际情况中,平均复杂度为O(nlogn)的算法已经是已知最优良的算法了。
已经证明,对于基于比较的算法(Comparison-based sorting algorithms),最优良的时间复杂度是O(nlogn)。
空间复杂度(Space Complexity)
空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度。有些算法在运行时不用在原输入所用运行空间外再有空间开销,这类算法成为“原地”算法(in-place),空间复杂度为O(1)。
===
常见排序算法的比较
算法名称 | 稳定性 | 平均时间复杂度 | 最坏情况时间复杂度 | 空间复杂度 | 备注 |
---|---|---|---|---|---|
冒泡排序 | 稳定 | n^2 | n^2 | 1 | 仅适用于数据量较少的情况 |
插入排序 | 稳定 | n^2 | n^2 | 1 | |
归并排序 | 稳定 | nlogn | nlogn | n | 经过并行化优化,最佳情况时间复杂度可以到达 logn |
选择排序 | 不稳定 | n^2 | n^2 | 1 | |
希尔排序 | 不稳定 | nlog^2 n | nlog^2 n | 1 | 代码规模小,运行时并不用申请多余的程序栈,运行效率高,适用于内存资源比较紧张的场合 |
堆排序 | 不稳定 | nlogn | nlogn | 1 | |
快速排序 | 不稳定 | nlogn | n^2 | 平均 logn 最坏情况 n | 典型的版本是不稳定的,但存在修改后是稳定的算法实现版本 |