希尔排序(比较排序)
要选定一个步长(比如4),那么0,4,8……它们是一组,1,5,9……他们是一组。分组排完之后再换成2步长,最后改成1,就行了。
实际使用时一般先设置步长为n/2,然后n/4……
组内排序直接插入就可以了。
只要是比较排序,不可能好过nlgn。
这一点可以使用决策树来证明:
可以看到,每个叶子代表一种排序结果,一共有n!个。
线性时间内的排序算法(非比较排序)
这种算法就不能弄比较了。要用空间换时间。
计数排序
算法流程
举个例子:
第一步:遍历整个数组,记录每种数据各自出现了几次。
第二步:看到C组,从第一个元素开始加上上一个元素的值,这样就记录了这个位置对应的元素在数组中排老几。
第三步:从最后一个数开始,先看看C,检查一下自己应该排哪一位,填进去。同时C组中对应数字要减一(这样的话,假如有一样的数,直接会填到前一位)
最后就是这样,从后到前遍历一遍就行。
为什么要从后到前?因为这样就是稳定的算法了。原本在前面的还在前面,不然就会搞反。
计数排序的缺点
显然,C的长度会受到A中最大元素K的影响,要是K特别大,那就完蛋了。
基数排序
算法流程
就是把数分成一位一位的,分别按照个位,十位,百位这样比较,比完就OK了。显然这样的算法不用太担心K很大。
最好从低位排起,还要用稳定的排序,这样一来这种算法也是稳定的了。
性能分析
这里的分析中,每一倘的排序是计数排序。可以看到基数排序就是对计数排序的改良,针对的就是计数排序K太大的问题。把数字分成很多块,这样每一趟用计数排序只有O(n+k)的复杂度(K就是2^r,这里r是指二进制数的位数,这里的使用场景是二进制数比较),最后乘以趟数b/r就行。
桶排序
算法流程
根据开头的一位放到对应链表里,每往表里加一个数用的方法是插入排序(例如23会插到21和26中间)最后再穿起来。可以看到这些数分布的越均匀越好,要是全都是一个数开头那就成插入排序了。要是足够均匀,那就是标准的线性时间内的排序。