该算法主要就是:找位置,如果不满足规则就让前一个元素往后移动,直到找到位置然后放进去;
因此该算法减少了数组中很多不必要的元素位置交换的操作;
插入式排序属于内部排序法,是对于欲排序的元素以插入的方式找寻该元素的适当位置,以达到排序的目的;
它的基本思想是:把n个待排序的元素看成(想象出来的)为一个有序表和一个无序表,开始时有序表只包含一个元素,无序表中包含n-1个元素,排序的过程中每次从无序表中取出第一个元素,把它的排序码依次与有序表的排序码进行比较,将它插入到有序表中的适当位置,使之称为新的有序表;
较难理解,脑子里面要时刻抽象出这个有序表和无序表;
图解
流程分析
1.把整个数组看成一个有序表和无序表,其中最开始有序表就只有arr[0]一个元素;
2.无序表有arr[1]-arr[n]元素;
3.每次从无序表的第一个位置取出元素,按照规则插入到有序表中;
注意:这个有序表和无序表是我们想象出来的,并不真实存在;
代码实现
/**
* @Author:Strine
* 插入排序的实现
* */
public static void getInsertSort(int arr[]){
long startTime = System.currentTimeMillis();
for (int i = 1; i < arr.length; i++) {
int insertIndex=i-1;// 有序表的第insertIndex个元素;
int insertVal = arr[i]; //相当于无序表中的第一个元素
while (insertIndex>=0&&insertVal<arr[insertIndex]){
//无需表的这个元素比有序表的最后一个元素那就让有序表的这个元素后移
arr[insertIndex+1]=arr[insertIndex];
//从后往前遍历有序表
insertIndex--;
}
//当循环完之后,说明找到了该元素的位置,也就是前一个位置的元素比当前元素还小了;
//如果说当前这个元素比之前的元素都要大,也就是说他就应该在这个位置,那么就不变
if (insertIndex+1!=i){
arr[insertIndex+1]=insertVal;
}
}
long endTime = System.currentTimeMillis();
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
System.out.println("共耗时:"+(endTime-startTime)+"毫秒");
}
代码简述
再次注意:这个有序表和无序表是我们想象出来的,并不真实存在;
1.首先我们要明确,我们需要遍历的是无序列表,而非有序列表,因此我们for循环应该从1开始;
2.那么我们有序列表的最后一个元素的索引值(Length-1)就应该是当前循环的次数i-1(当前循环次数也就是当前有序列表的长度);
3.因此我们对有序列表从后往前循环,直到循环到索引值为0的位置,或者有序列表的当前元素比我们要添加的这个元素还要小(大)为止=>由此得出了我们的while循环条件;
4.那么在while循环体内,也就是有序列表当前位置元素大于要添加的这个元素,那么我们就将有序列表中的这个元素后移;
5.然后让有序列表的索引值往前移动一位(自减一);
6.当跳出while循环之后,才说明真正找到了索引值;
7.最后完成这一轮的添加;
特点
在每次判断对比之后只会让原来的元素往后移动一位,并且让索引值自减;
在找到最终的索引时(也就是跳出while循环后)才会将当前元素添加进去,而不是在判断之后就立刻交换位置;
效果展示
性能测试
我们发现插入排序依旧是嵌套了两层循环,次数也是随着数组容量n的增大而增大,因此插入排序算法的时间复杂度依旧是O(n^2),我们还是初始化50000大小的随机数数组,来计算它的耗时,我们可以发现,它的速度甚至比选择排序还要快;