【概述】
直接插入排序是一种稳定的排序方法,其是插入排序中最简单的排序方法,类似于玩扑克时整理手牌的过程。
其基本思想是:依次将待排序序列中的每一记录插入到一个已排好序的序列中,直到全部记录都排好序。
其实现依靠双重循环完成,外层循环执行 n-1 次,内层循环执行次数取决于第 i 个记录前有多少个记录的关键码大于第 i 个记录的关键码。
【排序过程】
1.排序过程
具体的排序过程为:
- 将整个待排序的记录序列划分为有序区和无序区,初始时有序区为待排序记录序列中的第一个记录,无序区包括所有剩余待排序的记录
- 将无序区的第一个记录插入到有序区的合适位置中,从而使无序区减少一个记录,有序区增加一个记录
- 重复执行步骤 2,直到无序区中没有记录位置
2.实例
初始关键字: 『 6,5,3,1,8,7,2,4 』
第一趟排序: 『 6 』,5,3,1,8,7,2,4
第二趟排序: 6,5,3,1,8,7,2,4
『 6,5 』,3,1,8,7,2,4
第三趟排序: 5,6,3,1,8,7,2,4
5,『6,3』,1,8,7,2,4
『5,3』,6,1,8,7,2,4
第四趟排序: 3,5,6,1,8,7,2,4
3,『5,1』,6,8,7,2,4
『 3,1』,5 ,6,8,7,2,4
第五趟排序: 1,3,5 ,6,8,7,2,4
1,3,5,『6,8』,7,2,4
第六趟排序: 1,3,5 ,6 ,8,7,2,4
1,3,5,6,『8,7』,2,4
1,3,5,『6,7』,8,2,4
第七趟排序: 1,3,5 ,6 ,7,8,2,4
1,3,5,6,7,『8,2』,4
1,3,5,6,『7,2』,8,4
1,3,5,『6,2』,7,8,4
1,3,『5,2』,6,7,8,4
1,『3,2』,5,6,7,8,4
『1,2』,3,5,6,7,8,4
第八趟排序: 1,2,3,5,6,7,8,4
1,2,3,5,6,7,『8,4 』
1,2,3,5,6,『7,4』,8
1,2,3,5,『6,4』,7,8
1,2,3,『5,4』,6,7,8
1,2,『3,4』,5,6,7,8
结果: 『 1,2,3,4,5,6,7,8 』
排序过程 宏观过程
【时空复杂度分析】
在最好的情况下,待排序序列为正序,每趟排序只需与有序序列的最后一个记录的关键码比较一次,移动两次记录,那么总的比较次数为 n-1,总的移动次数为 2(n-1),因此,最优时间复杂度为 (n)
在最坏的情况下,待排序序列为逆序,第 i 趟插入时,第 i 个记录必须与前面的 i-1 个记录的关键码与哨兵比较,并且每比较一次就要做一次记录的移动,那么总的比较次数为 (n+2)(n-1)/2,总的移动次数为 (n+4)(n-1)/2,因此,最坏时间复杂度为 O(n^2)
在平均情况下,待排序序列中各种可能排列的概率情况相同,在插入第 i 个记录时平均要比较有序区中全部记录的一半,那么总的比较次数为 (n+2)(n-1)/4,总的移动次数为 (n+4)(n-1)/4,因此,平均时间复杂度为 O(n^2)
直接插入排序只需要一个记录的辅助空间,用于作为待插入记录的暂存单元和查找记录的插入位置过程中的哨兵。
【源程序】
void insertSort(int a[],int n){
for(int i=2;i<=n;i++){
int temp=a[i];//暂存待插入关键码,并设置哨兵
int j=i-1;
while(temp<a[j]&&j>=1){//寻找插入位置
a[j+1]=a[j];//记录后移
j--;
}
if(j!=i-1)//防止自我插入
a[j+1]=temp;
}
}