一、插入排序基本介绍
插入排序(insert Sort),简单来说就是将待排序的元素,拿出第一个元素作为有序列表,剩余的元素构成无序列表,然后将无序列表的元素一一插入到有序列表指定位置,从而达到排序的目的。直接上图:
二、插入排序思路分析
1.需求:给定一个待排序的数组arr,元素有n个,要求升序排列。
2.插入排序实现思想为:
1)将这n个待排序的元素看做是一个有序列表和无序列表
2)第一次排序有序列表只有第一个元素(1个元素必定有序),剩余n-1个元素构成无序列表
3)每次排序都从无序列表中顺序(从左到右)取出1个元素,插入到有序列表指定位置
4)重复步骤3,直到无序列表的所有元素都插入到有序列表,此时排序结束,整个数组已然有序
注意:由于只需要对无序列表的元素进入插入排序,所以排序次数一共为n-1次
三、插入排序图解
假设现在有一个数组arr = {1,5,3,4,7},要求使用插入排序进行升序排序,图解步骤如下:
四、插入排序代码实现
思路相信大家都已经很清楚了,这里就直接上代码了,代码注释很详细,关键就是在于如何找到需要插入的位置,我这里单独讲一下:
1.首先利用临时变量insertVal拷贝一份待插入元素的值(也就是每一轮无序列表的第一个元素的值)
2.由于待插入的值前面就是有序列表(升序),所以从右往左遍历有序列表,并且依次和待插入的值作比较,找到第一个比待插入的值小的元素,将待插入的元素插入到该元素后面
3.在比较查找第一个比待插入的值小的元素过程中,需要将有序列表扩大一个位置用来存放待插入的值,扩大的方式就是将原来待插入值的位置覆盖(也就是无序列表的第一个元素位置覆盖,因为前面已经用insertVal拷贝过一份值了),待插入的位置后面的有序元素依次向后覆盖,此时待插入的位置就腾出来,直接用insertVal的值代替即可。
public static void insertSort(int[] arr){
//外层循环,对无序列表的元素循环,无序列表的元素从整个数组arr第二个元素开始
for (int i = 1;i < arr.length;i++){
int insertVal = arr[i];//待排序的元素,是每一轮无序列表的第一个元素
int insertIndex = i - 1;//第一个比待插入的值小的元素下标,初始化为有序列表的右下标,循环找到这个位置
//在有序列表中循环查找第一个比待插入的值小的元素下标
while(insertIndex >= 0 && insertVal < arr[insertIndex]){
arr[insertIndex + 1] = arr[insertIndex];//后移覆盖留出待插入位置,第一次覆盖的就是无序列表的第一个位置,此时待插入的值已经有了备份insertVal
insertIndex--;//继续向有序列表左边寻找
}
//找到第一个比待插入值小的元素,将待插入的值插入到它后面,+1就是待插入位置
arr[insertIndex + 1] = insertVal;
}
}
五、插入排序的时间复杂度
因为是双重for循环,所以时间复杂度是O(n^2)
六、小结
1.插入排序是一种简单的排序,是后边学习希尔排序的基础,希尔排序就是在插入排序的基础之上进行了改进。改进在:当你使用插入排序对数组升序排序的时候,你会发现这个1的数值最小,但是又在数列末尾,需要进行大量的比较才能排到数组第一个元素,希尔排序就是通过将数组分为多个小组,对每一个小组进行直接插入排序,就达到了将数值小的且靠后的数提到前面来,大大提高了排序效率。
2.插入排序的难点就在于寻找插入位置这一步,仔细理解体会。