快速排序
快速排序在算法的实现上与归并排序有点类似,因为他们都采用了分而治之的思想,一想到分治我们又想到递归。快排时我们会随机选取一个元素作为主元,然后根据这个主元我们可以将剩下的数据分成两堆,一堆比主元小,一堆比主元大,然后就开始对这两堆进行递归的治。
我们来看看他的伪码描述
当我们学习归并排序时每次分治都是从中间劈开分的,所以快排时我们也应该遵循这样的原则,否则会出现下面的情况
如果这个序列已经有序我们选取了a[0]作为了主元,每次都会比较剩下的所有元素时间复杂度去到了O(N2),这个复杂度在排序里面是不理想的,身为快速排序这是很尴尬的递归的囧。
对快速排序优化时可以借助简单排序,当规模比较小的时候就不再用快排了,可以用选择排序来解决,这个比较小的规模我们把他叫做一个阈值。
再来看下快排的具体实现
:选取主元后,将其左边或右边的所有元素进到函数里来,搞两个指针(不是C里面的那个指针)指向最左边和最右边主元不包括在内,这里以主元左边为例,j指向主元前一个,i指向最左边那个,两个指针一起往中间动,当i指针指向的值大于主元时停下来,当j指针遇到小于主元的元素时停下来,两个都停下来之后将两指针所指元素交换,然后继续移动,如果遇到等于主元的元素也要停下来,之前说两指针都停下来之后要交换,这个时候其实还要判断一下i有没有越过j,没有就交换,如果i已经大于j了,就不再交换而是将主元与i所指位置元素交换。这样就结束了一次递归。
表排序
表排序是一种间接排序方法,解决一些不方便移动元素以达到排序目的的排序方法,你可能会问有什么不方便的,当我们要排序的是一些结构体且里面元素比较多,要改变他们的时间达到不可忽略时就显得不那么方便了。
跟简单排序方法不同的就是,新建一个table数组来存放排完序这个元素应该在的地方,也就是比较完大小之后,不是进行元素交换,而是记录位置到table数组里。
复杂度分析
m不可忽略
基数排序
前面所讲到的所有排序方法都是通过比较元素数值大小来实现排序的,无论你怎么优化,总能找到最坏的情况让你的时间复杂度去到O(nlogn),有没有可能打破这个魔咒呢,当然啦,那就是除非我们在比较大小之外还做些什么。
在介绍基数排序之前我们要知道桶排序,桶排序根据实际情况创建一定数量的桶,当读入元素属于这个桶时将其放入,这样排好并将其输出时间复杂度都是线性的这很不错。
这个时候就产生了基数排序,所以说基数排序是桶排序的扩展,它的基本思想是:将整数按位数切割成不同的数字,然后按每个位数分别比较。
具体做法是:将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。
通过基数排序对数组{53, 3, 542, 748, 14, 214, 154, 63, 616},它的示意图如下:
这么一看就很直白了