4.1.3 直接插入排序
直接插入排序是插入排序中最直观的算法(有点污啊)。它每一趟都会将一个待排序的元素按大小插入到已经排好序的序列的适当位置上,直到所有待排序的元素都插入为止。
下面看一个例子了解一下这个算法的执行流程:{5, 2, 4, 6, 3, 1}
有序 | 无序 | ||||
5 | 2 | 4 | 6 | 3 | 1 |
对于一个元素而言,怎样都是有序的,所以我们主要从第二个元素开始比较。
- 第一趟
当前有序部分为{5},我们第一趟要把2插入到有序序列部分,由于 2 < 5 2<5 2<5,所以2要插入到5前面。
有序 | 无序 | ||||
2 | 5 | 4 | 6 | 3 | 1 |
- 第二趟
把待排序元素4插入到有序序列部分。由于4小于5但是大于2,所以它要插入到2和5之间。
有序 | 无序 | ||||
2 | 4 | 5 | 6 | 3 | 1 |
以此类推,我们总共要比较5趟。所以我们又发现,对于直接插入排序算法,
n
n
n个元素的序列也只要进行n-1
趟排序。我们以上面的例子为例,写出直接插入排序算法的代码:
#include <cstdio>
int main(){
int a[10] = {5, 2, 4, 6, 3, 1};
// // 写法一:
// int flag, temp;
// // 进行n-1趟操作
// // 每趟操作确定一个待排序元素的位置
// for(int i=1; i<6; i++){
// // 从右开始循环遍历有序序列中的元素
// for(int j=i; j>0; j--){
// // 标记,记录跳出内层循环的时机
// flag = 0;
// // 如果待排序元素比有序序列中的元素小
// if(a[j] < a[j-1]){
// // 交换两个元素的位置
// temp = a[j];
// a[j] = a[j-1];
// a[j-1] = temp;
// // 同时改变标记,说明遍历未完成
// flag = 1;
// }
// // 如果标记没改变,说明当前位置就是待排序元素的最终位置
// if(flag == 0){
// // 跳出内层循环,进行下一趟的排序操作
// break;
// }
// }
// }
// 写法二:
int temp, j;
// 进行n-1趟操作
// 每趟操作确定一个待排序元素的位置
for(int i=1; i<6; i++){
// 存储待排序元素的值
temp = a[i];
// 存储待排序元素的前一个位置
j = i-1;
// 当待排序元素比有序序列中的元素小
while(j>=0 && temp<a[j]){
// 将有序序列中的元素向后移一个位置
a[j+1] = a[j];
// 将位置标记到下一个有序序列元素的位置
j--;
}
// 比较完之后将待排序元素放到正确的位置
a[j+1] = temp;
}
// 输出排列好的序列
for(int i=0; i<6; i++){
printf("%d", a[i]);
if(i<6-1){
printf(" ");
}
}
printf("\n");
return 0;
}
时间复杂度
:最坏情况下,需要进行n-1趟,第一趟比较1次,第二趟比较2次,……,第n-1趟比较n-1次。所以总次数为
n
2
−
n
2
\frac{n^2-n}{2}
2n2−n,复杂度为
O
(
n
2
)
O(n^2)
O(n2)。
空间复杂度
:又是算法的辅助存储空间不随n变化的情况,所以复杂度为
O
(
1
)
O(1)
O(1)。