插入排序
输入:n个数(a1,a2,…,an)。
输出:输入序列的一个排列(a1′,a2′,…,an’),使得a1’到an’为有序序列。
待排序的数称为关键字key。
插入排序与平时生活中打牌时,整理手中牌的顺序相似。最开始手中没有牌,我们从桌上摸起一张牌,将它插入正确的位置,在插入时,我们需要依次进行比较;任何时候,我们手中的牌都是已经排好序的,并且这些牌都是桌上那副牌最顶上的一张。
插入排序伪代码表示:
Insertion-sort(A)
//参数A是待排序数组
forj ← 2 to length[A]
dokey ← A[j]
▷ insert A[j] into the sorted sequence A[1…j-1]
//将A[j]插入已排好序的A[1…j-1]中
i← j-1
whileI > 0 and A[j] > key
doA[i+1] ← A[i]
I← i-1
A[i+1]← key
循环不变式与插入算法的正确性:
在外层for循环(循环变量为j)的每一轮迭代开始,包含元素A[1…j-1]的子数组构成已排好序的数组。元素A[j+1…n]对应未排序的子数组。实际上,已排好序的A[1…j-1]就是原数组A[1…n]的前j-1个元素,只不过已经排好序了。
循环不变式的证明:
初始化:循第一轮开始时,j=2,此时子数组只包含一个元素A[1],并且这个子数组是已经排好序的,因此循环第一轮开始是正确的。
能否保持:在外层for循环中,要将A[j-1]、A[j-2]、A[j-3]等元素向右移动一个位置,直到找到A[j]的适当位置为止,此时将A[j]插入。(类似归纳法)因此如果循环的迭代开始之前它是正确的,那么在下一次迭代开始之前,它也能保持正确。
终止:对于插入排序来说,当j大于n时,也就是j=n+1,外层for循环结束,外层for循环结束。在循环不变式中,将j替换为n+1,即有子数组A[1…n]包含了原先的A[1…n]中的元素,但是现在已经排好了序。因此整个数组就排好了序,算法正确。
复杂度及稳定性:
最坏时间复杂度:O(n^2)
最优时间复杂度:O(n)
平均时间复杂度:O(n^2)
排序算法稳定性:稳定
空间复杂度:O(1)
插入排序的C++语言实现:
void insertion_sort(int *A,int len)
{
for(int j=1; j<len; j++)
{
int key = A[j];
int i = j-1;
while (i>=0 && A[i]>key)
{
A[i+1] = A[i];
i–;
}
A[i+1] = key;
}
}