排序算法总结
下面简要总结了常用的一些排序算法。如有错误,还请大家指正、见谅~~谢谢~~
【1】插入排序:
是一个对少量元素进行排序的有效算法。实现比较简单。时间复杂度:O(n^2),空间复杂度:O(1)。是稳定的排序方法。
代码:
数据测试:
上述代码可以改进的一个地方是:在查找插入位置的时候可以采用二分查找,但是这样依然不可以把时间复杂度降低为O(nlogn),因为移动元素的复杂度没有降低。所以时间复杂度仍然是O(n^2)。
做此改进需要添加函数InsertLoc用于二分查找需要插入的位置,以及修改函数InsertionSort的实现。具体如下:
【2】选择排序
第一次找出A[0,...,n-1]的最小的元素,与A[0]交换,接着,找出A[1,...,n-1]的次小得元素,与A[1]互换。对A中头n-1个元素执行这一过程。时间复杂度:O(n^2),空间复杂度O(1)。是不稳定的排序方法。比如序列5 8 5 2 9,第一遍选择第1个元素5会和2交换,那么原序列中2个5的相对前后顺序就被破坏了,所以选择排序是不稳定的排序算法。
但是严蔚敏的《数据结构》书上面Page289页说,所有时间复杂度为O(n^2)的简单排序都是稳定的。不知道为什么?求指导~~
其给出的简单排序的伪代码:
代码:
【3】合并排序
采用分治法。将n个元素分成各含n/2个元素的子序列,用合并排序法对两个子序列递归的排序(子序列长度为1时递归结束),最后合并两个已排序的子序列得到结果。时间复杂度:O(nlogn),空间复杂度:O(n)。是稳定的排序方法。
代码:
如果不使用哨兵元素,需要修改Merge函数,如下:
【4】冒泡排序
每一趟都比较相邻两个元素,若是逆序的,则交换。结束的条件应该是“在一趟排序过程中没有进行过交换元素的操作”。时间复杂度:O(n^2),空间复杂度O(1)。是稳定的排序。
【5】快速排序
它是对冒泡排序的一种改进。它的基本思想是:通过一趟排序将待排序元素分成两个部分,其中一部分元素比另一部分元素小。再分别对这两部分元素进行排序。以达到整个元素序列有序。时间复杂度:O(nlogn),空间复杂度O(logn),是不稳定的算法。
代码:
一些好的参考资料:不同排序算法间的比较:http://commons.wikimedia.org/wiki/File:SortingAlgoComp.png
一些排序算法的 C 及 Pascal 实现 :
http://www.nocow.cn/index.php/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95
最后,简要比较一下各排序算法,转自维基百科:
简要比较
名称 | 数据对象 | 稳定性 | 时间复杂度 | 空间复杂度 | 描述 | ||
---|---|---|---|---|---|---|---|
平均 | 最坏 | ||||||
插入排序 | 数组、链表 | √ | O(n2) | O(1) | (有序区,无序区)。把无序区的第一个元素插入到有序区的合适的位置。对数组:比较得少,换得多。 | ||
直接选择排序 | 数组 | × | O(n2) | O(1) | (有序区,无序区)。在无序区里找一个最小的元素跟在有序区的后面。 对数组:比较得多,换得少。 | ||
链表 | √ | ||||||
堆排序 | 数组 | × | O(nlogn) | O(1) | (最大堆,有序区)。从堆顶把根卸出来放在有序区之前,再恢复堆。 | ||
归并排序 | 数组、链表 | √ | O(nlogn) | O(n) +O(logn) , 如果不是从下到上 | 把数据分为两段,从两段中逐个选最小的元素移入新数据段的末尾。可从上到下或从下到上进行。 | ||
快速排序 | 数组 | × | O(nlogn) | O(n2) | O(logn) ,O(n) | (小数,枢纽元,大数)。 | |
Accum qsort | 链表 | √ | O(nlogn) | O(n2) | O(logn) ,O(n) | (无序区,有序区)。把无序区分为(小数,枢纽元,大数),从后到前压入有序区。 | |
决策树排序 | √ | O(logn!) | O(n!) | O(n) <O(logn!) <O(nlogn) | |||
计数排序 | 数组、链表 | √ | O(n) | O(n+m) | 统计小于等于该元素值的元素的个数 i,于是该元素就放在目标数组的索引 i位。(i≥0) | ||
桶排序 | 数组、链表 | √ | O(n) | O(m) | 将值为 i 的元素放入i 号桶,最后依次把桶里的元素倒出来。 | ||
基数排序 | 数组、链表 | √ | 一种多关键字的排序算法,可用桶排序实现。 |
- 均按从小到大排列
- n 代表数据规模
- m 代表数据的最大值减最小值