插入算法的简单介绍,本人也是个小白。写在这里既是加深自己的理解,也希望能帮助一下那些想要认识该算法的朋友。由于本人也是多从网上学来,如内容有雷同之处,请勿见怪。再次声明本文仅作学习交流。
1. 插入算法。
插入算法其实说白了,就是一个操作---比较。比较的对象则是需要排序的元素和已经排好的序列。
比如数组a[0,…,i-1]和a[i]比较。a[0,…,i-1]就被认为已经排好序了,a[i]是待排元素。如果a[i]大于a[i-1],自然a[i]大于a[0,…,i-1]中每一个元素。不需要进行任何操作。只需要开始下一轮比较-----将i后移。也就是继续取数组下一个元素和a[0,…,i]比较。如果a[i]小于a[i-1]则继续向前比较直到找到a[0,…,i-1]中大于a[i]的元素或者下标为0处(前面数字都比较完了也没找到,那么a[i]应该是前i个元素中最小的)。然后将该元素之后的所有元素(一直到i-1)这个位置后移一位,将a[i]插入到该元素后面。这样数组前i个元素就都有序了。接着开始下一轮的比较。
插入算法的开始是默认数组第一个元素就是有序的,所以比较从下标1开始,一直到n-1,总共需要比较n-1次。
列表说明插入算法的过程。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
3 | 4 | 1 | 3 | 4 | 5 | 1 | 8 | 7 |
注:第一行为数组下标,第二行为对应元素
第一次比较:默认下标为0的序列有序,则a[1]和a[0]比较。4>3,不予操作。此时数组可以看到前两个数有序。即a[0]<a[1];下面将取第三个元素和数组前两个进行比较。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
3 | 4 | 1 | 3 | 4 | 5 | 1 | 8 | 7 |
这里用红色表示前面提到的有序数组a[0,…,i-1]
第二次比较。取a[2]和a[1]比较,a[2]<a[1],则继续向前比较a[2]<a[0],此时已经比较完了,a[2]最小,比较终止的位置下标元素全部后移。最后将a[2]放到比较终止位置上,本次比较结束。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
2 | 3 | 4 | 3 | 4 | 5 | 1 | 8 | 7 |
如此下去,一共需要比较n-1次。
代码如下:
public static void insert_sort(int a[], int n){ //这里因为是直接被静态方法main()调用,所有声明为static.参数a 为数组,n为数组长度。
int i,j,k;
for(i=1;i<n;i++){ //i从1开始进行比较,共需要比较n-1次。这里强掉一下:你只有比较到最后一个元素才知道究竟第一个元素是不是全局最小。
for(j=i-1;j>=0;j--){ //下标为i的元素和它之前的元素逐次比较
if(a[i]>a[j]) //找到比a[i]大的已排好序列中的位置即插入位置j+1
break;
}
int value=a[i]; //防止在接下来的后移中a[i]被覆盖丢失。
for(k=i-1;k>j;k--){ //j到i之间元素逐次后移一位,不包括下标为j的那个。
a[k+1]=a[k];
}
a[k+1]=value;//将a[i]放到第j+1个位置。此时K==j的。
}
上述代码是先找到插入位置,然后后移元素。也可以用一个for循环完成。如下:
public static void insert_sort(int a[],int n){
int i,j;
for(i=1;i<n;i++){
int temp=a[i];
for(j=i-1;j>=0&&a[j]>temp;j--) //只要a[j]大于temp就移位。<span style="font-family: Arial, Helvetica, sans-serif;">注意j>=0这个条件要放在前面,因为j--时可能出现j=-1的情况</span><pre name="code" class="java"> //根据for循环的情况,如果你把a[j]>a[j+1]放在j>0前面,将会报错数组下标出现-1的情况。
a[j+1]=a[j]; a[j+1]=temp;//最后插入}
上面也是在最后执行的插入操作,说白了也是先找到位置,边找边移位。其实也可以边找位置边执行位置交换。即只要a[i]<a[j]二者就交换位置。这样就省掉了最后的插入操作。代码如下:
public static void insert_sort(int a[],int n){
int i,j;
for(i=1;i<n;i++){
for(j=i-1;j>=0&&a[j]>a[j+1];j--){ //这里是两两比较,每比较一次交换一次。直到a[i]>a[j].注意j>=0这个条件要放在前面,因为j--时可能出现j=-1的情况
//根据for循环的情况,如果你把a[j]>a[j+1]放在j>0前面,将会报错数组下标出现-1的情况。
temp=a[j+1];
a[j+1]=a[j];
a[j]=temp;
}
}
插入排序最坏的情况是原数组与你想排的正好相反。如你想从小到大,可实际待排数组正好从大到小。每次比较都需要移动所有排好数组元素的位置。O(n2),最好的是已经有序O(n)。平均情况是O(n2).从代码也可以看出时间复杂度上有两个for循环。再次强调插入排序只有在结束才能确定最终的最大最小值。因为每次比较排序都只是针对钱i个元素。
读者还有不懂可以参阅http://blog.csdn.net/morewindows/article/details/6665714。本文主要代码也是参阅与此。本文仅作交流,若有不当,敬请留言。