插入排序
本文针对的读者: 熟悉C++语法,期望进一步加深对插入排序的理解或者第一次接触插入排序的同学
插入排序的思路和平时人们在打扑克牌时整理手中的牌的思路是完全一致的。
下面举一个实际的例子:
在C++中,假设有一个int型的数组中存了未排序的一组数,如何采用插入排序的方法进行排序?
仔细的回想一下整理扑克牌时的过程,刚开始手中没有牌,然后从牌堆拿一张牌,这时候手里有一张牌,
当然此时手里的牌是有序的,继续从牌堆里拿牌,然后插入到手中的适当的位置,使手中的牌有序,
接着继续从牌堆拿牌,并且插入手中,当牌堆中的牌拿完了之后,手中的牌也是排好序的,这样就完成了
插入排序。
从上面描述的过程中可以看出,这里有一个一直在循环的操作模式,拿牌并且插牌,我们就以拿牌为基准进行循环,
每拿到一次牌就进行一次循环,在这次循环里,将拿到的牌插入已排好序的手牌中。check一下初始情况,用自己的脑子
启动这个循环,跑一遍,注意结束时状态。
下面写一下伪代码:
INSERTION-SORT(A, len) #传入的是一个数组,以及它的大小
#初始状态: 取A[0]为初始已排序的牌集,牌堆为A[1..len-1]
for i<-1 to len -1
x <- A[i] #取出A[i]
#将x插入已排好序的A[0...i-1]中,将x插入到A[0...i-1]的位置,其实也包括A[i]这个位置,严格来说是将x插入到A[0...i]的位置取决于从后往前第一个小于x的元素位置
j <- i-1 #从i-1开始往前找第一个<=x的元素,如果找到大于x的元素则向后移位,那么这里在起始的时候,i始终可以被i-1覆盖,因为A[i]已经作为插牌提出
while(A[j] > x && j >= 0)
j--; #继续往后找
A[j+1] <- A[j]; #这里进行移位操作
A[j+1] <- x #上面代码结束时,在check j的时候退出,则总能保证j+1为空,这时需将x插入在该位置。
从以上的伪代码可以看出,插入排序的模式其实很简单,难点在于如何插入,因为插入的时候回出现多种情况:
1.往前探查第一个元素即小于等于x,这是一个边界情况
2.往前探查所有的元素都大于x,这也是一种边界情况
3.其他则,探查的位置的左右两边都有元素
考虑到这三种情况,直接把代码写出来会比较难,当然如果以第三种情况为基础写代码,则比较容易写出,但是兼顾其他两种状态,
在同时考虑三种情况的下写代码则相对较难,这个时候,以一般情况写出代码,再测试边界情况,不失为一个降低复杂度的好方法。
熟悉了之后,自然而然就记下来是最终的一种状态。
下面给出实际的C++测试代码:
/** * algorithm name: Insert Sort * implemented by: Ivan Jobs * date: 2012.5.1 * email: ivan1377@163.com */ #include <cstdio> #define MAX 100 /** * Insert-Sort * len is size of array a. */ void InsertSort(int a[], int len){ int i, j; for(i=1;i<len;++i){ // start from 1 to len-1 int key = a[i]; // insert key into sorted array a[0,1,..,j] j = i-1; while(a[j]>=key && j>=0){ a[j+1] = a[j]; j--; } a[j+1] = key; } } int li[MAX]; int main(){ printf("Enter several integers:\n"); int i = 0; int val; while(scanf("%d", &val) == 1 && val != 0){ li[i++] = val; } int len = i; printf("len is %d\n", len); InsertSort(li, len); printf("The sorted result is:"); for(i=0;i<len;++i) printf(" %d", li[i]); printf("\n"); return 0; }
以上有不妥之处,欢迎指正:)