简介
直接插入排序是插入排序的一种。它思想是将一个新的数据插图到已经排好序的有序表中,然后得到一个新的有序表。因为思想和代码很简单,我们仍然直接通过代码进行讲解。完整代码见:https://github.com/kfcyh/sort/tree/master/insertsort。
代码讲解
首先提供代码:
void insertsort(SqList L)
{
int i, j;
for (i = 2; i < L->length; i++)
{
if (L->r[i] < L->r[i - 1]) //需要将L->r[i]插入有序表
{
L->r[0] = L->r[i]; //设置哨兵
for (j = i - 1; L->r[j] > L->r[0]; j--)
L->r[j + 1] = L->r[j]; //数据后移
L->r[j + 1] = L->r[0]; //插入到正确位置
}
}
}
下面我们以排序一副手牌为例讲解,手牌为{5,3,4,6,2}。
- 外循环for为主循环,循环插入各数据, i i i起始为2表示 r [ 1 ] r[1] r[1]已插入,它是有序表的基础。我们将哨兵初始化为0。
-
i
=
2
i=2
i=2时,
r
[
i
]
=
3
<
r
[
i
−
1
]
=
5
r[i]=3<r[i-1]=5
r[i]=3<r[i−1]=5,执行插入调整操作。首先将哨兵
r
[
0
]
=
r
[
i
]
r[0]=r[i]
r[0]=r[i],然后进入内循环进行排序,
j
j
j从
i
−
1
i-1
i−1(有序表的最大数)开始逐个与哨兵比较,若大于哨兵则后移该数据,直到找到小于等于哨兵的数据,然后将数据插入到该数据后面。此时我们将数据5后移,然后将3插入到5的前面。
3.再次循环, i = 3 i=3 i=3, r [ i ] = 4 < r [ i − 1 ] = 5 r[i]=4<r[i-1]=5 r[i]=4<r[i−1]=5,同上,将5后移,然后将4插入到3的后面。
-
再次循环, i = 4 i=4 i=4, r [ i ] = 6 > r [ i − 1 ] = 5 r[i]=6>r[i-1]=5 r[i]=6>r[i−1]=5,此时不需要调整顺序直接插图到5的后面。
-
再次循环, i = 5 i=5 i=5, r [ i ] = 2 < r [ i − 1 ] = 6 r[i]=2<r[i-1]=6 r[i]=2<r[i−1]=6,同上,将3,4,5,6后移,然后将2插入到哨兵后面。此时插入并排序完毕。
性能分析
综上所述,直接插入排序和简单选择排序一样,不需要除哨兵外的任何辅助空间。对于时间复杂度,最好的情况是待排序的数据本就是有序的,如{2,3,4,5,6},此时比较次数为 n − ∑ i = 2 n 1 n-\sum_{i=2}^n1 n−∑i=2n1,没有移动次数。时间复杂度为 O ( n ) O(n) O(n),最坏情况是待排序表为逆序,如{6,5,4,3,2},此时需要比较 ∑ i = 2 n i = 2 + 3 + . . . + n = ( n + 2 ) ( n − 1 ) 2 \sum_{i=2}^ni=2+3+...+n=\frac{(n+2)(n-1)}{2} ∑i=2ni=2+3+...+n=2(n+2)(n−1),移动次数为 ∑ i = 2 n ( i + 1 ) = 2 + 3 + . . . + n = ( n + 4 ) ( n − 1 ) 2 \sum_{i=2}^n(i+1)=2+3+...+n=\frac{(n+4)(n-1)}{2} ∑i=2n(i+1)=2+3+...+n=2(n+4)(n−1)。因此直接插入排序的时间复杂度为 O ( n 2 ) O(n^2) O(n2),但和简单选择排序相比性能更好。