注:以下排序默认为升序排序。
稳定性:指的是排序的过程中是否会改变多个相同的值的相对次序,如果会改变则是不稳定的。
冒泡排序,选择排序,插入排序是最简单的排序方法。
排序方法:扫描的过程中,比较相邻两个数的大小关系,如果存在逆序就交换这两个数,这样每趟可以保证最后一个数,也就是最大的数,一步步交换上去,如气泡上浮一样,回归到正确的位置。
时间复杂度:
稳定性:稳定。对于两个相同的值,不会发生交换。
代码实现:
排序方法:扫描的过程中,每次选择剩余未排序的数组中选择最小值与未排序部分第一个值进行交换,从而使得未排序部分的第一个位置得到正确的值。
时间复杂度:
稳定性:不稳定。例如,3 3 2 2 3 3 可以发现两个3的位置改变了。
代码实现:
排序方法:每次取未排序部分的数组,将其插入到前半已经排序后的数组内,类似打牌时整理牌序的方法,插入到前面整理好的数组内的合适的位置。
时间复杂度:
稳定性:稳定。相同的值符合大于等于关系,并不会插入到相同值的前面。
代码实现:
排序方法:每次选择特定的增量,对这个增量下的子序列进行直接插入排序。
最好时间复杂度:
最坏时间复杂度:【选取d={1, 2, 4, 8, …2k}大到小】,$O(nlog{n}log{n})$【选取2m*2^n次大到小的集合】
关于时间复杂度的证明:主要考虑对于两个不同增量的序列的插入排序,两者的结果都是可以互相继承的;以及相关其他复杂度的 分析
稳定性:不稳定,因为不同序列相同的值的位置可能改变。
代码实现:
排序方法:“挖坑填数”,取出需要排序区间的第一个数作为基数,利用双指针方法,整理当前数组,使得这个数组成为坑左边均为小于等于基数的数,坑右边都是大于等于基数的数,最后把基数填入这个位置,此处基数回到正确的位置。然后分成两个区间,递归分治,重复上述操作。
一般时间复杂度:
最坏时间复杂度(例如数组已经有序的时候):
稳定性:不稳定。例如 6 3 3 经过一次的填坑得到 3 3 _ 3的次序发生了改变。
代码实现:
排序方法:利用标号关系构造一个无序堆,通过堆调整,形成一个有序的大顶堆。每次取堆顶的数和未排序数的最大标号,即堆底最后一个叶子交换位置,此时,最后一个叶子是当前未排序的数中最大的数,已经回到正确的位置,离开堆。之后,调整堆,维护大顶堆的性质,等待下一次交换。
关于堆调整:如果父节点最大不交换,如果父节点不是最大,则要交换左右儿子中较大的一个,交换后,可以使得原来那个较小儿子所在的子树的父节点变成较大儿子,这样保证较小儿子的子树符合二叉堆的性质,并且根节点也符合条件,但是,可能会影响较另外子数成堆,所以,为了维护堆的性质,要一直交换下去,直到符合性质,最坏可能要交换到叶子,但是这样的交换不超过次,因为每次交换都可以使得近似大小的另一子树符合堆的性质,需要维护的堆的性质的节点数倍减,直至单个节点,单个节点符合堆的性质。
时间复杂度:
时间复杂度分析:开始的堆调整次,之后每个数取出后的堆调整的交换次数取决于二叉堆的深度,由于二叉堆是一个完全二叉树,所以深度不超过所以一趟的交换次数不超过次。
稳定性:不稳定。如果是全相等的堆,仍然会进行交换。
代码实现:
排序方法:利用分治的思想,将数组不断划分,到单个数,然后递归合并起来,利用双指针的手法,将两个有序数组合并成一个有序的数组。
时间复杂度:
稳定性:稳定,合并的数组的时候,如果两个值相同的话会按照原先的顺序依次放入到临时数组当中。
代码实现:
排序方法:将输入值的值域划分成若干个区间,分别放入到桶中,再用其他排序方法对桶内的元素进行排序,类似分块,分治。
时间复杂度:取决于桶内排序算法的时间复杂度以及分类后所在的桶的数目,如果使用堆排序来进行桶内排序的话,并且最后均匀地分入到k个桶内,那么时间复杂度是,当桶足够多时,覆盖了值域的时候,便是的计数排序。
稳定性:取决于给桶内排序的算法的稳定性,如果是插入排序就是稳定的,如果是堆排序或者快速排序就是不稳定的。
代码实现:
排序方法:计数排序是桶排序中桶的数量和值域长度相同的时候,就是一次读入数据,放入到对应值的桶内,最后遍历值域输出排序好的数组。
时间复杂度:其中k是值域长度,n是元素数目。
稳定性:稳定。按序读入相同值,按序拷贝出来。笔者想了想,直接用一维数组有点难以体现稳定性,如果用可变长数组或者链表来实现的话就能维护相同值的相对次序,每个链表存入该值的id。或者用二维数组。
代码实现:
排序方法:基数排序相当于对每一位作计数排序。
时间复杂度:其中k是最大数的某进制形式下的数码长度(通常是十进制)
原理说明:手写高位到低位分别是主要关键字,次要关键字,,,次次关键字,最次关键字。首先我们根据最低位排序,如果后面高位不相同,会按照高位排序,如果高位相同的话,但是低位不相同,计数排序具有稳定性,不会改变低位已经排好的顺序。
稳定性:稳定。同上。
注意:基数排序的需要非负整数,如果有负数的话需要调整为非负整数。
代码实现: