一、插入排序:稳定,时间复杂度O(n^2)
想象你在打扑克牌,一开始左手是空的,接着右手开始从桌上摸牌,并将其插入到左手的一把牌中的正确位置上。为了找到这个正确位置,我们需要从右到左将它与手中的牌比较,直到找到合适的位置插入。整个过程的特点是,左手的牌是排好序的了。
详见: 插入排序
二、选择排序:不稳定,时间复杂度O(n^2)
每趟从未排序部分选出最小的元素,然后通过交换将其添加到已排序部分中。
详见: 选择排序
三、冒泡排序:稳定,时间复杂度O(n^2)
将待排序的元素看作是竖着排列的“气泡”,较小的元素比较轻,从而要往上浮。在冒泡排序算法中我们要对这个“气泡”序列处理若干遍。所谓一遍处理,就是自底向上检查一遍这个序列,并时刻注意两个相邻的元素的顺序是否正确。如果发现两个相邻元素的顺序不对,即“轻”的元素在下面,就交换它们的位置。显然,处理一遍之后,“最轻”的元素就浮到了最高位置;处理两遍之后,“次轻”的元素就浮到了次高位置。在作第二遍处理时,由于最高位置上的元素已是“最轻”元素,所以不必检查。一般地,第i遍处理时,不必检查第i高位置以上的元素,因为经过前面i-1遍的处理,它们已正确地排好序。
详见: 冒泡排序
四、归并排序:稳定,时间复杂度 O(nlog n),空间O(n)
分解:将n个元素分成各含n/2个元素的子序列;
解决:用归并排序法对两个子序列递归地排序;
合并:合并两个已排序的子序列以得到排序结果。
合并思想:
桌面上有两堆已排好序的牌(比如最上面的牌最小),牌面朝上。我们的任务是将两堆牌合并成一堆有序的牌。
下面开始取牌:从两堆牌顶上的两张牌中选取较小的一张,将其取出,面朝下放到输出堆中。如果反复取牌直到其中一堆牌为空,接下来只要把剩下那堆牌(如果有的话)的所有牌都取出并放到输出堆中即可。
详见: 归并排序
五、堆排序:不稳定,时间复杂度 O(nlog n)
堆排序是一种树形选择排序,在排序过程中,将A[n]看成是完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系来选择最大的元素。
详见: 堆排序
六、快速排序:不稳定,时间复杂度 平均O(nlog n),最差O(n^2),空间O(log n)->递归的栈空间
快排基于分治模式,其基本思想:
分解:从序列中取出一个数作为基准数,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边,从而得到两个子序列。
解决:递归调用快速排序,对两个子序列进行排序。
合并:因为子序列是就地排序的,所以合并不需要任何操作。
详见: 快速排序
七、希尔排序:不稳定,时间复杂度 平均O(nlogn),最差O(n^s) 1 < s < 2
在直接插入排序算法中,每次插入一个数,使有序序列只增加1个节点,并且对插入下一个数没有提供任何帮助。如果比较相隔较远距离(称为 增量)的数,使得数移动时能跨过多个元素,则进行一次比较就可能消除多个元素交换。D.L.shell于1959年在以他名字命名的排序算法中实现了这一思想。算法先取某个增量d,所有距离为d的倍数的记录放在同一个组中。先在各组内进行直接插入排序,然后再用一个较小的增量对它分组,在每组中再进行排序。当增量减到1时,整个要排序的数被分成一组,排序完成。
八、计数排序:稳定,线性时间
计数排序假设n个输入元素都是0到k之间的整数,基本思想是对每个元素x,确定出小于x的元素个数,之后便可以将x直接放到合适的位置。(需注意元素相等的情况)
详见: 计数排序
八、基数排序:稳定,线性时间
我们要对一副扑克牌排序,可以这样做:先不管牌的大小,先对花色(比如红桃、黑桃、方块、梅花)排序,之后再根据牌的大小排序,于是一副牌就按花色、大小排好了。
对于数字,我们可以先对最低位排序,再对次低位排序。。最后对最高位排序。
详见: 基数排序
八、桶排序:稳定,线性时间
假设所有元素均匀分布在区间[0,1)上,将该区间划分成n个相同大小的子区间(称为桶),之后,将相应的元素放到对应范围的桶里面,对各个桶里的元素进行排序,最后按次序把各个桶里的元素列出来即可。
桶排序很快,大多时候比快排还快,不过很耗费空间。
详见: 桶排序
各个算法都有其适用的情况,所以没有绝对的优劣之分,具体问题要具体分析。要是有人问你,哪个排序算法最好,千万别往坑里跳。o(^▽^)o
下面提一下一些有趣的排序:
(以下是并行化的排序算法)
奇偶排序(Odd-even Sort)
采样排序(Sample Sort)
每天进步一点点,Come on!
(●’?’●)
本人水平有限,如文章内容有错漏之处,敬请各位读者指出,谢谢!