1.动画展示
2.思路分析
例如从小到大排序:
1. 从第二位开始遍历,
2. 当前数(第一趟是第二位数)与前面的数依次比较,如果前面的数大于当前数,则将这个数放在当前数的位置上,当前数的下标-1,**
3. 重复以上步骤,直到当前数不大于前面的某一个数为止,这时,将当前数,放到这个位置,
1-3步就是保证当前数的前面的数都是有序的,内层循环的目的就是将当前数插入到前面的有序序列里
4. 重复以上3步,直到遍历到最后一位数,并将最后一位数插入到合适的位置,插入排序结束。
思路2:
插入排序(Insertion Sorting)的基本思想是:把n个待排序的元素看成为一个有序表和一一个无序表,开始时有序表中只包含-一个元素,无序表中包含有n-1个元素,排序过程中每次从无序表中取出第一个元素, 把它的排序码依次与有序表元素的排序码进行比较,将它插入到有序表中的适当位置,使之成为新的有序表。
根据思路分析,每一趟的执行流程如下图所示:


3.复杂度分析
1. 时间复杂度:插入算法,就是保证前面的序列是有序的,只需要把当前数插入前面的某一个位置即可。
所以如果数组本来就是有序的,则数组的最好情况下时间复杂度为O(n)
如果数组恰好是倒=倒序,比如原始数组是5 4 3 2 1,想要排成从小到大,则每一趟前面的数都要往后移,一共要执行n-1 + n-2 + … + 2 + 1 = n (n-1) / 2 =** 0.5 n^s2 - 0.5 n次,去掉低次幂及系数,所以最坏情况下时间复杂度为O(n^2)
平均时间复杂度(n+n2 )/2,所以平均时间复杂度为O(n^2)
2. 空间复杂度:插入排序算法,只需要两个变量暂存当前数,以及下标,与n的大小无关,所以空间复杂度为:O(1)*
4.代码实现
最近看的
分为有序的队伍和无序的队伍
逐步扩大有序队伍,缩减无序队伍
public class InsertSort {public static void main(String[] args) {int[] a = {5, 8, 5, 2, 6, 9,2, 3};insert(a);System.out.println(Arrays.toString(a));}public static void insert(int[] arr){//i代表的是带插入的元素索引for (int i = 1; i < arr.length; i++) {int t = arr[i];//代表带插入的元素,保存索引i的值,方便空出来,和其他元素交换int j = i-1;while (j>=0){if (t<arr[j]){arr[j+1] = arr[j];}else {break;//前面是有序的,退出循环,减少比较次数}j--;}arr[j+1] =t;//j+1是空出来的位置,也就是前面t要去的位置System.out.println(Arrays.toString(arr));}}}
输出结果: [5, 8, 5, 2, 6, 9, 2, 3] 红色为有序的范围,逐渐扩大,就是将无序的元素从有序队伍中找它合适的位置
[5, 5, 8, 2, 6, 9, 2, 3] 然后它后面的有序队伍逐个向后移动,腾出来的位置就给这个待插入的元素
[2, 5, 5, 8, 6, 9, 2, 3] break;的存在就是当待插入的都比有序队伍的大,则这个元素的位置就无须
[2, 5, 5, 6, 8, 9, 2, 3] 改变
[2, 5, 5, 6, 8, 9, 2, 3]
[2, 2, 5, 5, 6, 8, 9, 3]
[2, 2, 3, 5, 5, 6, 8, 9]
[2, 2, 3, 5, 5, 6, 8, 9]
public class InsertSort {public static void main(String[] args) {int arr[] = {10, 7, 9, 3, 2};System.out.println(Arrays.toString(arr));// System.out.println("排序前:"+Arrays.toString(arr));insert(arr);// System.out.println("排序前:"+Arrays.toString(arr));}private static void insert(int[] arr) {int insertVal = 0;int insertIndex = 0;for (int i = 1; i < arr.length; i++) {//等待插入的值insertVal = arr[i];insertIndex = i-1;//即arr[1]的前面的这个数的下标while(insertIndex >= 0 && insertVal < arr[insertIndex]){ //>则是从大到小arr[insertIndex +1] =arr[insertIndex]; //将原先等待插入的那个值先替换成要插入的位置的值 {101, 34, 119, 1}; => {101,101,119,1}insertIndex--;//退出循环}// 当退出while循环时,说明插入的位置找到, insertIndex + 1// 举例:理解不了,我们一会 debug//这里我们判断是都需要赋值if (insertIndex+1 != i) {arr[insertIndex + 1] = insertVal; //{101, 34, 119, 1}; => {34, 101, 119, 1}}System.out.println("第"+i+"轮插入");System.out.println(Arrays.toString(arr));}}}
逐步推导
//使用逐步推导的方式来讲解,便利理解//第1轮 {101, 34, 119, 1}; => {34, 101, 119, 1}//{101, 34, 119, 1}; => {101,101,119,1}//定义待插入的数int insertVal = arr[1];int insertIndex = 1-1;//即arr[1]的前面的这个数的下标//给insertVal找到插入的位置//说明//1. insertIndex >= 0 保证在给insertVal 找插入位置,不越界//2. insertVal < arr[insertIndex] 待插入的数,还没有找到插入位置//3. 就需要将 arr[insertIndex] 后移while(insertIndex >= 0 && insertVal < arr[insertIndex]){arr[insertIndex +1] =arr[insertIndex];insertIndex--;//退出循环}arr[insertIndex+1] =insertVal;System.out.println("第"+1+"轮插入");System.out.println(Arrays.toString(arr));//第2轮insertVal = arr[2];insertIndex = 2-1;//即arr[1]的前面的这个数的下标while(insertIndex >= 0 && insertVal < arr[insertIndex]){arr[insertIndex +1] =arr[insertIndex];insertIndex--;//退出循环}arr[insertIndex+1] =insertVal;System.out.println("第"+2+"轮插入");System.out.println(Arrays.toString(arr));//第三轮insertVal = arr[3];insertIndex = 3-1;//即arr[1]的前面的这个数的下标while(insertIndex >= 0 && insertVal < arr[insertIndex]){arr[insertIndex +1] =arr[insertIndex];insertIndex--;//退出循环}arr[insertIndex+1] =insertVal;System.out.println("第"+3+"轮插入");System.out.println(Arrays.toString(arr));//第4轮insertVal = arr[4];insertIndex = 4-1;//即arr[1]的前面的这个数的下标while(insertIndex >= 0 && insertVal < arr[insertIndex]){arr[insertIndex +1] =arr[insertIndex];insertIndex--;//退出循环}arr[insertIndex+1] =insertVal;System.out.println("第"+4+"轮插入");System.out.println(Arrays.toString(arr));*/
运行截图
