插入排序和冒泡排序
插入排序
直接插入排序是最简单的排序方法,每次将一个待排序的记录,插入到已经排好序的数据序列当中,得到一个新的长度增1的有序表
算法步骤
1) 设待排序的记录存储在数组 r[1],r[2]…r[n] 中,可以把第一个记录$r[1]$ 看作一个有序序列
2) 依次将 r[i](i=2,….,n) 插入到已经排好序的序列 r[1,….,i-1] 当中,并保持有序性, 我们看到 r[0] 是空的,它的作用是保存将要插入到数组当中的数字的。
比如2比12小,那么 r[0] = 2 ,12 后移,再将2 从r[0]移到r[1].
16比12大,什么都不需要做。
30比16大,什么也不需要做。
28比30小,令r[0] = 28 ,30 往后移动一格,再让28和16比,因为28>16 所以16 不动,28插入到16和30 之间。
非递减即为允许相等的递增
算法分析
时间复杂度
最好情况下,待排序序列本身是正序的(如待排序序列是非递减的,题目要求也是非递减排序) , 每个记录只需要和前一个记录比较一次, 不小于前一个记录, 则什么都不用做, 总的比较次数为
$\Sigma _{i=2}^n 1 = n-1$
那么最好的情况下直接插入排序的时间复杂度为$O(n)$
最坏情况下,待排序序列本身是逆序的(如待排序序列是非递增的,题目要求是非递减排序),每个记录都需要比较 i 次,包括和前 i-1 记录比较,并和哨兵 r[O]比较,总的比较次数为:
$\Sigma_{i=2}^n i = \frac{(n+2)(n-1)}{2}$
最坏情况下,直接插入排序的事件复杂度为 $O(n^2)$
平均情况下,若大排序序列出现各种情况的概率均等,则可取最好的情况和最坏的情况的平均值。平均情况下,直接插入排序的时间复杂度也为 $O(n^2)$
空间复杂度
直接插入排序使用了一个辅助空间r[0] ,空间复杂度为 $O(1)$
稳定性
直接插入排序时,已经有序的序列中的记录比待排序记录大时才向后移动,和待排序记录相等时不向后移动, 因此两个相等的记录在排序前后的位置顺序是不变的。例如, 上例中排序前16在16*
之前, 排序后16仍在16*
之前。 因此直接插入排序是稳定的排序方法。
直接插入排序每次将待排序记录插入到一个有序序列中,在有序序列中查找待排序记录 的插入位置时,折半查找的方法比顺序查找效率更高,采用折半查找插入位置的插入排序称为折半插入排序, 有兴趣的读者可以自己动手试试。
练习题
- 什么排序算法可能会出现:在最后一趟开始之前,所有元素都不在最终位置上这一情况? 直接排序算法,最后一趟待排序元素是最小的,之前所有位置上的元素都要后移
- 待排序表为反序时,直接插入排序需要进行 $(n)(n-1)/2$ 次比较(从前往后依次需要1,2,$\cdots$ n-1次) ; 待排序表 为正序的时候,只需进行 n-1 次比较
代码一览
1 |
|
冒泡排序
冒泡排序是一种最简单的交换排序算法,通过两两比较关键字,如果逆序就交换,使关键字大的记录像泡泡一样冒出来放在尾部。重复执行若干次冒泡排序,最终得到有序序列。
算法步骤
1) 设待排序的记录存储在数组 r[1,…,n ] 当中,首先第一个记录和第二个记录关键字比较,若逆序则交换;然后第二个记录和第三个记录关键字比较,…, 以此类推,直到第 n-1 个记录和第n个记录关键字比较完毕为止。第一趟排序结束,关键字最大的记录在最后一个位置。
2)第二趟排序,对前n-1 个元素进行冒泡排序,关键词次大的记录在n-1 位置
3)重复上述过程,知道某一趟排序中没有进行交换记录为止,说明序列已经有序。
到了第七趟排序的时候,发现没有交换,所以立即停止。
1 |
|