插入排序
插入式排序属于内部排序法, 是对于欲排序的元素以插入的方式找寻该元素的适当位置, 以达到排序的目的。
插入排序的问题: 当需要排序的数组中小值越靠后, 就会循环判断次数越多
插入排序的演变过程(从小到大)
把 n 个待排序的元素看成为一个有序表和一个无序表,开始时有序表中只包含一个元素, 无序表中包含有 n-1 个元素, 排序过程中每次从无序表中取出第一个元素, 把它的排序码依次与有序表元素的排序码进行比较, 将它插入到有序表中的适当位置, 使之成为新的有序表。
public class InsertSort {
public static void main(String[] args) {
int[] arr = { 101, 34, 119, 1 };
insertSort(arr);
}
// 插入排序
public static void insertSort(int[] 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--;
}
// 当退出while循环时,说明插入的位置找到, insertIndex + 1
// 举例:理解不了,我们一会 debug
arr[insertIndex + 1] = insertVal;
System.out.println("第1轮插入");
System.out.println(Arrays.toString(arr));
// 第2轮
insertVal = arr[2];
insertIndex = 2 - 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));
// 第3轮
insertVal = arr[3];
insertIndex = 3 - 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));
}
}
/*
第1轮插入
[34, 101, 119, 1]
第2轮插入
[34, 101, 119, 1]
第3轮插入
[1, 34, 101, 119]
*/
插入排序实例代码
public class InsertionSortApp {
public static int[] setArray(int capacity) {
int[] arr = new int[capacity];
for (int i =0; i < capacity;i++) {
arr[i] = (int) (Math.random() * capacity);
}
return arr;
}
/** 插入排序方法
* - 从无序表到有序表的转移过程*/
public static void insertionSort(int[] arr) {
/** 定义待插入的数值& 指定下标 -1, 也就是前一个元素下标
* - 从第2个(1)元素开始与第一个元素(0)比较交换, 依次判断
* */
int insertValue = 0;
int insertIndex = 0;
for (int i = 1; i < arr.length; i++) {
/** 定义待插入的数*/
insertValue = arr[i];
/** 待插入元素的下标 -1*/
insertIndex = i - 1;
/**
* 1. 为了下标不越界 insertIndex >= 0
* 2. 待插入的数(当前数: insertValue),
* 与原数组前一个数(下标-1的元素: arr[insertIndex])比
* 较 insertValue < arr[insertIndex]
* 3. 将 arr[insertIndex]值覆盖当前数的原数组
* 位(arr[insertIndex + 1]), 也就是后移
* */
while (insertIndex >= 0 && insertValue < arr[insertIndex]) {
arr[insertIndex + 1] = arr[insertIndex];
insertIndex--;
}
/** 有在 while循环中处理过, 意味着 insertIndex下标递减过,
同时已锁定元素位, 所以可以将待插入的数(insertValue)插入到指
定位置* */
if (insertIndex + 1 != i) {
arr[insertIndex + 1] = insertValue;
}
System.out.println("i=" + i + ": " + Arrays.toString(arr));
}
}
public static void main(String[] args) {
int arr[] = {9, 8, 7, 10, 2};
System.out.println("排序前 " + Arrays.toString(arr));
/** 开始插入排序*/
insertionSort(arr);
}
/*
输出:
> 排序前 [9, 8, 7, 10, 2]
* 8<9=true; arr[insertIndex + 1] = arr[insertIndex]; 89 交换
i=1: [8, 9, 7, 10, 2]
* 7比较9
* 7比较8
i=2: [7, 8, 9, 10, 2]
i=3: [7, 8, 9, 10, 2]
* 2比较10
* 2比较9
* 2比较8
* 2比较7
i=4: [2, 7, 8, 9, 10]
*/
插入排序效率(一般)
/** 生成长度为 100000的随机值数组, 用于与其它算法对比排序效率*/
int[] arr = setArray(100000);
System.out.println("开始时间 " +
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()));
/** 开始插入排序*/
insertionSort(arr);
System.out.println("结束时间 " +
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()));
/*
输出:
> 开始时间 2020-10-14 15:36:44
> 结束时间 2020-10-14 15:36:45
> */