一、常用排序算法
各种常用排序算法 | ||||||||
类别 | 排序方法 | 时间复杂度 | 空间复杂度 | 稳定性 | 复杂性 | 特点 | ||
最好 | 平均 | 最坏 | 辅助存储 |
| 简单 |
| ||
插入 排序 | 直接插入 | O(N) | O(N2) | O(N2) | O(1) | 稳定 | 简单 |
|
希尔排序 | O(N) | O(N1.3) | O(N2) | O(1) | 不稳定 | 复杂 |
| |
选择 排序 | 直接选择 | O(N) | O(N2) | O(N2) | O(1) | 不稳定 |
|
|
堆排序 | O(N*log2N) | O(N*log2N) | O(N*log2N) | O(1) | 不稳定 | 复杂 |
| |
交换 排序 | 冒泡排序 | O(N) | O(N2) | O(N2) | O(1) | 稳定 | 简单 | 1、冒泡排序是一种用时间换空间的排序方法,n小时好 2、最坏情况是把顺序的排列变成逆序,或者把逆序的数列变成顺序,最差时间复杂度O(N^2)只是表示其操作次数的数量级 3、最好的情况是数据本来就有序,复杂度为O(n) |
快速排序 | O(N*log2N) | O(N*log2N) | O(N2) | O(log2n)~O(n) | 不稳定 | 复杂 | 1、n大时好,快速排序比较占用内存,内存随n的增大而增大,但却是效率高不稳定的排序算法。 2、划分之后一边是一个,一边是n-1个, 这种极端情况的时间复杂度就是O(N^2) 3、最好的情况是每次都能均匀的划分序列,O(N*log2N) | |
归并排序 | O(N*log2N) | O(N*log2N) | O(N*log2N) | O(n) | 稳定 | 复杂 | 1、n大时好,归并比较占用内存,内存随n的增大而增大,但却是效率高且稳定的排序算法。 | |
基数排序 | O(d(r+n)) | O(d(r+n)) | O(d(r+n)) | O(rd+n) | 稳定 | 复杂 |
| |
注:r代表关键字基数,d代表长度,n代表关键字个数 |
1、冒泡算法
2、直接选择排序
3、快速排序
4、直接插入排序
5、堆排序
1.堆分为最大堆和最小堆,相当于完全二叉树,最大堆:要求节点的元素都不要小于其孩子,最小堆:要求节点元素都不大于其左右孩子
2、过程演示:
a.将初始待排序关键字序列(R1,R2....Rn)构建成大顶堆,此堆为初始的无序区
b.将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,......Rn-1)和新的有序区(Rn)
c.由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,......Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2....Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成
步骤一:
构造初始堆(升序采用最大堆,降序采用最小堆)。
a.首先得到无序序列结构
b.从最后一个非叶子节点开始,从左至右,从上至下进行调整(注意:交换之后可能造成被交换的孩子节点不满足堆的性质,因此每次交换之后要重新对被交换的孩子节点进行调整)。
c.找到第二个非叶节点,进行交换调整
d.当调整完之后,发现已经调整过的【1,3,4】号节点结构混乱,不满足最大堆要求,继续调整,直至得到初始最大堆。
步骤二:
将堆顶元素与末尾元素进行交换,使末尾元素最大。
继续调整其他元素使其满足最大堆要求。
重复两个步骤,得到第二大元素,后续交换,反复进行,直至整个数组变得有序。
3、代码实现:
4、时间复杂度:
堆排序的时间复杂度为O(N*log2N)
5、算法稳定性:
堆排序是一种不稳定的排序算法。
因为在堆的调整过程中,关键字进行比较和交换所走的是该节点到叶子结点的一条路径,因此对于相同的关键字就可能出现排在后面的关键字被交换到前面来的情况。
5、希尔排序
1、希尔排序是插入排序的一种,是直接插入排序的改进版本。
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序;随着增量逐渐减少,每组包含的关键词越来越多,最后,增量减至1时,整个文件恰好被分成一组,算法终止。
增量序列:{n/2,(n/2)/2...1},称为增量序列
2、步骤演示:
a.选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
b.按增量序列个数k,对序列进行k 趟排序;
c.每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
3、代码实现:
4、时间复杂度:
希尔排序的平均时间复杂度为O(N1.3)
5、稳定性:不稳定
由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的。