插入排序
插入式排序属于内部排序法,对于欲排序的元素以插入的方式找寻该元素的适当位置,以达到排序的目的。
排序思想
把n个待排序的元素看成为一个有序表和一个无序表,开始时有序表中只包含一个元素,无序表中包含有n-1个元素,排序过程中每次从无序表中取出第一个元素,把它的排序码依次与有序表元素的排序码进行比较,将它插入到有序表中的.适当位置,使之成为新的有序表。
图解
举个例子,上面的图数据太长,我们来个简单的例子,加入有个数组是[17,3,25,14,20,9]
插入排序怎么排序呢?
首先第一个元素17看成是有序表,那么剩下的就是无序表
第一次插入:插入3,跟有序表比较,比17小,按照我们的从小到大规则,插入到17前面
成为 [(3,17) 25,14,20,9]
第二次插入:插入25,跟有序表[3,17]比较,比我们17大,放在17后面
成为 [(3,17,25) 14,20,9]
第三次插入:插入14,跟有序表(3,17,25)比较,比25小,往前找,比17小再往前,比3大,介于3,17之间。插入成为 [(3,14,17,25) 20,9]
依次类推,直至无序表没有数据
总共要进行n-1次插入
请听题:
科大有一宿舍学生,成绩分别是:101,34,119,1
请用插入排序,将他们的成绩从小到大排列
代码实现
package com.wang.sort;
import java.util.Arrays;
/**
* @author 王庆华
* @version 1.0
* @date 2020/12/24 16:05
* @Description TODO
* @pojectname 插入排序算法
*/
public class InsertSort {
public static void main(String[] args) {
int[] arr = {
101,34,119,1};
insertSort(arr);
}
//插入排序
//逐步推到
//第一次插入101,34,119,1====>34,101,119,1
public static void insertSort(int[] arr){
//定义待插入的数 34是下标为0的元素
int insertValue = arr[1];
int insertIndex = 1-1;//跟谁比较,跟前面的数比较
//给insertValue找到插入位置
while (insertIndex >=0 && insertValue <arr[insertIndex]){
//insertIndex >=0保证我们找位置的时候不越界
//insertValue <arr[insertIndex]==》说明我们还没找到位置
//没有找到位置,说明我们的insertIndex代表的值大,往后面走
arr[insertIndex+1] = arr[insertIndex];
//数组变成了 101,101,119,1
//我们的34被保存到了insertValue中
insertIndex--;
}
//当退出while循环时,位置找到
arr[insertIndex+1] = insertValue;
System.out.println("第一次插入后的数组:"+ Arrays.toString(arr
));
//第二轮
insertValue = arr[2];
insertIndex = 2-1;
while (insertIndex >=0 && insertValue <arr[insertIndex]){
//insertIndex >=0保证我们找位置的时候不越界
//insertValue <arr[insertIndex]==》说明我们还没找到位置
//没有找到位置,说明我们的insertIndex代表的值大,往后面走
arr[insertIndex+1] = arr[insertIndex];
//数组变成了 34,101,119,1
//我们的34被保存到了insertValue中
insertIndex--;
}
//当退出while循环时,位置找到
arr[insertIndex+1] = insertValue;
System.out.println("第二次插入后的数组:"+ Arrays.toString(arr));
//第三轮
insertValue = arr[3];
insertIndex = 3-1;
while (insertIndex >=0 && insertValue <arr[insertIndex]){
//insertIndex >=0保证我们找位置的时候不越界
//insertValue <arr[insertIndex]==》说明我们还没找到位置
//没有找到位置,说明我们的insertIndex代表的值大,往后面走
arr[insertIndex+1] = arr[insertIndex];
//我们的34被保存到了insertValue中
insertIndex--;
}
//当退出while循环时,位置找到
arr[insertIndex+1] = insertValue;
System.out.println("第三次插入后的数组:"+ Arrays.toString(arr));
}
}
为什么退出的时候,我们的insertIndex要+1呢?因为我们一开始定义这个insertIndex的时候减去了一个1,跟我们的图解差不多
图解中,每插入一个元素的时候,我们发现有一个绿色的标记,那个就是我们的insertIndex所处的位置,好比243,排序3,我先跟谁比较?这个时候3的下标是2,他要先跟4比较也就是下标为1的元素,那我们insertIndex就是2-1,正好是4,比较发现小,那么我们进入while循环,数组变成244,insertIndex变成了0,再去判断循环,这个时候的insertValue >arr[insertIndex],现在的insertIndex就是绿色柱子2,我们3比绿色数字要大,当时比刚才那个有小,所以我们插入的位置就在insertIndex+1的位置
插入排序算法
/**
* @author 王庆华
* @version 1.0
* @date 2020/12/24 16:05
* @Description TODO
* @pojectname 插入排序算法
*/
public class InsertSort {
public static void main(String[] args) {
int[] arr = {
101,34,119,1};
insertSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void insertSort(int[] arr){
for (int i = 1; i <arr.length; i++) {
//从1个元素开始,不需要减一,减一的话我们的最后一个元素就不插入了
int insertValue = arr[i];
int insertIndex = i-1;//跟谁比较,跟前面的数比较
//给insertValue找到插入位置
while (insertIndex >=0 && insertValue <arr[insertIndex]){
//insertIndex >=0保证我们找位置的时候不越界
//insertValue <arr[insertIndex]==》说明我们还没找到位置
//没有找到位置,说明我们的insertIndex代表的值大,往后面走
arr[insertIndex+1] = arr[insertIndex];
//数组变成了 101,101,119,1
//我们的34被保存到了insertValue中
insertIndex--;
}
arr[insertIndex+1] = insertValue;
}
}
}
外层for循环控制我从从那个位置开始准备插入,起始位置是arr[1],因为arr[0]我们当成了有序列表
那么外层循环就是arr[1],找位置arr[2]找位置……
内层while循环是用来找位置的,判断是不是我们要插入的位置,也就是我们推导过程说的那样
当然有人会问,我们的arr[insertIndex+1] = insertValue;地方如果恰好是相等的,不用交换呢?你可以加一个if去判断,但是这个优化,效果不大
问题
我们看简单的插入排序可能存在的问题.
数组arr = {2,3,4,5,6,1}这时需要插入的数1(最小),这样的过程是:
{2,3,4,5,6, 6}
{2,3,4,5,5, 6}
{2,3,4,4,5, 6}
{2,3,3,4,5, 6}
{2,2,3,4,5, 6}
{1,2,3,4,5, 6}
结论:当需要插入的数是较小的数时,后移的次数明显增多,对效率有影响.
那么如何优化插入排序呢?=====>希尔排序
这就是插入排序(直接插入排序),有什么地方说错了,说的不好,大家可以交流下