3.7 KiB
排序
基本概念
- 排序:将一个数据元素的任意序列重新排列成一个按关键字有序的序列。
- 内部排序:待排序的记录存放在计算机的内存中所进行的排序操作称为内部排序。
- 外部排序:待排序的记录数量很大,以致内存一次不能容纳全部记录,在排序过程中需要访问外存的排序过程称为外部排序。
- 稳定的排序:比如一个序列是“1,4,3,3*,2”,按从小到大排序后变成“1,2,3,3*,4”,就叫做稳定排序,即3和3*相对顺序不变。如果相同关键字的顺序发生了改变,则是不稳定的排序。稳定性的需要看具体的应用场景。
- 内部排序的算法性能取决于算法的时间复杂度和空间复杂度,而时间复杂度一般是由比较和移动次数决定的。外部排序除此之外还要考虑磁盘读写速度和次数。
- 大部分排序算法都仅适用于顺序存储的线性表。
插入排序
直接插入排序
每次将一个待排序的记录按其关键字大小插入到前面已排好序的子序列中,直到全部记录插入完成为止。
空间复杂度为$O(1)$。
时间复杂度主要来自对比关键字,移动元素,若有n个元素,则需要n-1趟处理。
最好情况是原本的序列就是有序的,需要n-1趟处理,每次只需要对比一次关键字,不用移动元素,时间复杂度为$O(n)$。
最坏情况是原本的序列是逆序的,需要n-1趟处理,第i趟处理需要对比关键字i+1次,移动元素i+2次,时间复杂度是$O(n^2)$。
所以平均时间复杂度是$O(n^2)$。
直接插入排序算法是稳定的。
如果使用链表实现直接插入排序,移动元素的次数变少了,但是关键字对比次数仍然时$O(n^2)$,从而整体时间复杂度依然是$O(n^2)$。
二分插入排序
也称为折半插入排序,是对直接插入排序的优化,在寻找插入位置时使用二分查找的方式。
当data[mid]==data[i]时,为了保证算法的稳定性,会继续在mid所指位置右边寻找插入位置。
当low>high时停止折半查找,并将[low,i-1]内的元素全部右移,并把元素值赋值到low所指的位置。
空间复杂度为$O(1)$。
二分插入排序是稳定的。
比起直接插入排序,比较关键字的次数减少,移动元素的次数没变,所以总体时间复杂度为$O(n^2)$。
希尔排序
希尔排序也是对直接插入排序的优化。直接插入排序对于基本有序的序列排序效果较好,所以就希望序列能尽可能基本有序。从而希尔排序的思想就是先追求表中元素部分有序,然后逐渐逼近全局有序。
先将整个待排序元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的),分别进行直接插入排序,然后缩小增量重复上述过程,直到增量为1。
增量序列的选择建议是第一趟选择元素个数的一半,后面不断缩小到原来的一半。
空间复杂度为$O(1)$。
而时间复杂度和增量序列的选择有关,目前无法使用属性手段证明确切的时间复杂度。最坏时间复杂度为$O(n^2)$,在某个范围内可以达到$O(n^{1.3})$。
希尔排序是不稳定的。
希尔排序只适用于顺序表而不适合用于链表,无法快速进行增量的访问。
交换排序
交换排序即根据序列中两个元素关键的比较结构然后交换这两个记录在序列中的位置。
冒泡排序
从后往前或从前往后两两比较相邻元素的值,若逆序则交换这两个值,直到序列比较完。这个过程是一趟冒泡排序。每一趟都会让关键字最小或最大的一个元素到未排序队列的第一个或最后一个。