基本知识
- 直接插入排序的最好情况下时间复杂度为O(n),最坏情况下时间复杂度为O(n^2)。
- 直接插入排序只需要一个记录的辅助空间,其空间复杂度为O(1)
- 直接插入排序是稳定的排序算法,适用于待排序记录数较少且基本有效的情况。当待排序的记录数目过多时,插入排序的性能直线下降。
举例
假如8个记录的关键字序列为(56, 68, 25, 45, 90, 38, 10, 72)
基本思想
-
插入前需要找到插入位置,移动记录空出插入位置,第i趟插入排序将记录L.rcd[i+1]插入到有序区L.rcd[1..i]中
-
其中中括号中的序列表示有序序列,中括号后面的序列表示无序序列,每一趟的直接插入排序就是将无序序列中的第一个记录,即待插入记录,插入到有序序列中的合适位置,使得有序序列的长度增加一个,只包含一个记录的序列是有序的,因此第一趟插入排序是将存储在2号单元的记录插入到前面有序序列中去。
-
首先需要查找插入位置,查找插入位置,可以在有序序列中从前到后进行查找,也可以从后向前进行查找,查找结束,发现待插入记录38应插入到记录25和45之间,若要实现插入操作,还需要将记录45到90向后移动一个位置, 以空出插入位置,将记录38插入。
-
在移动记录时,若选择从前到后的顺序移动记录,后面的记录会被覆盖,因此必须从后向前移动记录,记录90向后移动时,会覆盖掉待插入记录38,因此,移动前还需要将记录38暂存他处。
-
那么对应第i趟插入排序,就是将存储在i+1号单元的待插入记录插入到有序区[1..i]号单元的合适位置中,很显然要实现该算法,插入前需要找到插入位置,移动记录空出插入位置。
核心程序实现
void InsertSort(RcdSqList &L) {
// 对顺序表L作直接插入排序。
int i, j;
for (i = 1; i<L.length; ++i) {
if(L.rcd[i+1].key<L.rcd[i].key) {
// 需将L.rcd[i+1]插入有序序列
L.rcd[0] = L.rcd[i+1]; // 先将记录L.rcd[i+1]保存在空闲的0号单元
j = i+1;
do {
j--;
L.rcd[j+1] = L.rcd[j]; // 记录后移
} while(L.rcd[0].key<L.rcd[j-1].key); // 判断是否需要继续移动
L.rcd[j] = L.rcd[0]; // 插入
}
}
}