//直接插入排序
public class InsertSort {
//让数组中的数字从小到大排列
public static void main(String[] args) {
int a[] = {49, 38, 65, 97, 76, 13, 27, 49, 78, 34, 12, 64, 5, 4, 62, 99, 98, 54, 56, 17, 18, 23, 34, 15, 35, 25, 53, 51};
int temp = 0;
for (int i = 1; i < a.length ; i++) {
int j = i - 1;
temp = a[i]; //a[i]是要插入的那个数,将数值负值给temp
for (; j >= 0 && temp < a[j]; j--) {
a[j+1] =a [j]; //将大于temp的值整体后移一个单位
}
a[j+1] = temp;
}
for (int i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
}
}
基本思想:在要排序的一组数中,假设前面(n-1)[n>=2] 个数已经是排好顺序的,现在要把第n个数插到前面的有序数中,使得这n个数也是排好顺序的。如此反复循环,直到全部排好顺序。
在编辑的过程中还是要时不时去翻看原来的代码,虽然之前背过但是忘得七七八八。自己试着写的时候发现写不出
来,着实感到很羞愧。最后还是相当于把代码抄了一遍吧……
在自己试着写算法的过程中发现主要是有两个难点:
1. i 和j 的值定义的位置,是应该作为局部变量还是作为全局变量定义呢?在for的初始化表达式里定义还是在for循环前面定义(第一个初始化表达式,第二个循环变量判定表达式,第三个循环变量修正表达式)。
答:这里要搞清楚temp和a[i]的关系,当temp被赋值插入的数,a[i]代表的是当前已插入数组的最后一个位置的数。
2.代码中的j=i-1;但是什么时候用i-1,什么时候用j也是需要注意的。
答:当我把第16行的a[j+1]错写成i的时候,排序错误。算法的逻辑出现了错误。
然后我试着将上述的算法进行修改成由大到小排序的结果。
//直接插入排序
public class InsertSort2 {
//让数组中的数字从小到大排列
public static void main(String[] args) {
int a[] = {49, 38, 65, 97, 76, 13, 27, 49, 78, 34, 12, 64, 5, 4, 62, 99, 98, 54, 56, 17, 18, 23, 34, 15, 35, 25, 53, 51};
int temp = 0;
for (int i = 1; i < a.length ; i++) {
int j = i - 1;
temp = a[i]; //a[i]是要插入的那个数,将数值负值给temp
for (; j >= 0 && temp > a[j]; j--) { //仅仅改变判断符号即可
a[j+1] =a [j]; //将小于temp的值整体后移一个单位
}
a[j+1] = temp;
}
for (int i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
}
}
结果还是错将第13行写成 a[j] = a[j+1]; 导致逻辑出现错误排序失败。
直接插入排序的时间复杂度,数组长度为n:
1、最优情况:当给出的序列是已经按要求排好序的时候,每个插入的数只需与前面的数比较一次,(外层for循环)循环n-1趟,每一趟只进行一次比较,但是并不发生交换,也就是说循环体中的内容没有被执行到,但是内层for循环的判断表达式也执行了n-1次,所以复杂度为O(n)。(这里有一点要注意:不交换并不代表没有进行比较!)。
2、最坏情况:当给出的序列是按照要求相反的顺序进行排序的,外层for循环循环n-1趟,那么每一趟的比较次数分别为1,2,3……n-1,一共比较(n-1)(n-1+1)/2≈n²/2次,时间复杂度为O(n^2)。
3、平均时间复杂度是O(n^2)。
空间复杂度:算法中用了一个temp变量来存放临时数据。所需要的辅助存储空间对输入量来说是一个常数,所以空间复杂度为O(1)。
稳定性:排序完成后,相同的数之间的相对位置并没有发生改变,稳定。
适用情况:直接插入排序适用于初始记录基本有序(正序)的情况,当初始记录无序,n较大时,此算法时间复杂度较高,不宜采用。
总结:了解并不等于理解,只知道思想还需知道如何实现,就算简单的算法也要去实践,不断剖析才能真正地理解更深,才能掌握。