当我们玩扑克牌时,我们从桌子上一张一张牌拿起来并插入到拿牌的手中,这就是插入排序的思想。我们分析一下,在手上的牌是局部有序的,而当我们新拿上一张新牌时,这张牌应该插入到手中那局部有序牌的适当位置,为了进行正确的插入,我们从右往左进行比较(也许许多人都不是这样思考的,但这不失为一个好例子),直到找到一个适当的位置,然后进行插入。插入时,我们手上的一部分牌要进行相应的移动,以给新牌插入的空间,这就是插入排序的一个过程。 重复此过程,直到拿完所有的牌,此时手上的牌也是有序的了。
当进行数组排序时,我们将数组也分成两部分,其中arr[0...i-1]是局部有序的,局部有序意味着新的元素可能会插入到[0,i-1]的任何位置,而不是像选择排序那样插入到位置i中,arr[i...n-1]是无序的。每次运行就是为了将下标i的元素插入到下标[0,i-1 ]的适当位置,并更新i的值。下面是实现代码:
void insert_sort(int arr[], int len)
{
int temp, next_i;
for (int i = 1; i < len; i++)
{
temp = arr[i];//未排好序的第一个数
//Insert arr[i] into the sorted squence arr[0..i-1]
next_i = i - 1;//已经排好序的最后一个关键码的标,从这里开始向后进行比较,找到适当的位置进行插入
while (next_i>-1 && arr[next_i] > temp)
{
arr[next_i+1] = arr[next_i];//将元素右移
next_i = next_i - 1;//继续沿着左边移动,寻找适当的位置进行插入
}
//当退出while时,已经找到了适合的位置插入temp
arr[next_i + 1] = temp;
}
}
变量temp保存的是要插入的元素,next_i保存的是进行比较的元素下标,如果该元素大于temp,那么就将该元素后(右)移一位,而next_i前(左)移一位,其值为下一个要比较的元素下标。如果此时next_i下标的元素小于或等于temp,则相应的位置已经找到,这个位置下标就是next_i+1,将temp插入到这个位置,而这个位置之前的元素已经向前移动了,插入是正确的。
需要说明的是,这个代码的实现参考了《算法导论(第三版)》中的插入排序伪代码,程序的思想和实现都比较简洁。而反观严蔚敏和陈文博编著的《数据结构及应用算法教程》书中,其插入排序的实现则要繁琐很多。从很多方面看,这都是一本非常烂的教材。