解题思路
1.核心思想是,将数组分为左右两侧,左侧为有序数组,右侧为待排序数组,将右侧待排序数组一次插入到左侧有序数组中,每次插入通过比较大小选择合适的位置插入
2.将数组0位置上的数与位置1上的数进行对比,如果1位置上的数更大则不变,反之将1位置上的数插入到0左侧。
3.此时0,1位置上有序,将2位置上的数与1进行比较,如果2位置上的数更大则不变,反之继续与0位置上的数进行比较,如果还是2位置上的数更大,则插入在0,1间,反之插入在0左侧。
3.一次循环,不断将右侧的数,往左侧有序数组中插入。
/**
* @author Wengong lin
* @date 2023/4/19 15:03
* @description 插入排序
*/
public class InsertionSort {
private static int COMPARE_NUMBER = 0;
private static int SWAP_NUMBER = 0;
public static void main(String[] args) {
int [] arr = {5,3,8,1,6,9,7,2,4};
System.out.println("排序前:");
printArr(arr);
insertionSort(arr);
System.out.println("排序后:");
printArr(arr);
System.out.println("比较次数:" + COMPARE_NUMBER);
System.out.println("交换次数:" + SWAP_NUMBER);
}
public static void insertionSort(int []arr) {
for (int i = 1; i < arr.length; i++) {
for (int j = i; j > 0; j--) {
if (arr[j] < arr[j-1]) swap(arr,j-1,j);
COMPARE_NUMBER++;
}
}
}
public static void swap(int[] arr, int i, int minIndex) {
SWAP_NUMBER ++;
int temp = arr[minIndex];
arr[minIndex] = arr[i];
arr[i] = temp;
}
public static void printArr(int [] arr) {
for (int item : arr) {
System.out.print(item + " ");
}
System.out.println();
}
}
样例输出
代码优化1
优化思路:将右边的数往左侧有序数组中插入的时候,如果已经找到插入位置了,就可以不用继续比较下去
/**
* @author Wengong lin
* @date 2023/4/19 15:03
* @description 插入排序
* 优化思路:将右边的数往左侧有序数组中插入的时候,如果已经找到插入位置了,就可以不用继续比较下去
*/
public class InsertionSortOpt1 {
private static int COMPARE_NUMBER = 0;
private static int SWAP_NUMBER = 0;
public static void main(String[] args) {
int [] arr = {5,3,8,1,6,9,7,2,4};
System.out.println("排序前:");
printArr(arr);
insertionSort(arr);
System.out.println("排序后:");
printArr(arr);
System.out.println("比较次数:" + COMPARE_NUMBER);
System.out.println("交换次数:" + SWAP_NUMBER);
}
public static void insertionSort(int []arr) {
for (int i = 1; i < arr.length; i++) {
for (int j = i; j > 0 && arr[j] < arr[j-1]; j--) {
swap(arr,j-1,j);
COMPARE_NUMBER++;
}
}
}
public static void swap(int[] arr, int i, int minIndex) {
SWAP_NUMBER ++;
int temp = arr[minIndex];
arr[minIndex] = arr[i];
arr[i] = temp;
}
public static void printArr(int [] arr) {
for (int item : arr) {
System.out.print(item + " ");
}
System.out.println();
}
}
样例输出
代码优化2
优化思路:使用一个“key”变量来保存当前要插入的元素。然后我们从数组的第一个元素开始遍历,将未排序的元素一个一个地插入到已排序的部分中。在插入一个元素时,我们比较它和后面的元素,将“key”比它小的元素往后移动,直到找到一个位置可以插入。
/**
* @author Wengong lin
* @date 2023/4/19 15:03
* @description 插入排序
* 优化思路:使用一个“key”变量来保存当前要插入的元素。然后我们从数组的第一个元素开始遍历,
* 将未排序的元素一个一个地插入到已排序的部分中。在插入一个元素时,我们比较它和后面的元素,
* 将“key”比它小的元素往后移动,直到找到一个位置可以插入。
*/
public class InsertionSortOpt2 {
private static int COMPARE_NUMBER = 0;
public static void main(String[] args) {
int [] arr = {5,3,8,1,6,9,7,2,4};
System.out.println("排序前:");
printArr(arr);
insertionSortOpt(arr);
System.out.println("排序后:");
printArr(arr);
System.out.println("比较次数:" + COMPARE_NUMBER);
}
public static void insertionSortOpt(int []arr) {
for (int i = 1; i < arr.length; i++) {
int key = arr[i];
int j = i;
while (j > 0 && key < arr[j-1]) {
arr[j] = arr[j-1];
j--;
COMPARE_NUMBER++;
}
arr[j] = key;
}
}
public static void printArr(int [] arr) {
for (int item : arr) {
System.out.print(item + " ");
}
System.out.println();
}
}
样例输出
对数器测试
import java.util.Arrays;
import java.util.Random;
/**
* @author Wengong lin
* @date 2023/4/19 10:56
* @description 对数器
*/
public class DataChecker {
public static int[] generateRandomArray() {
Random random = new Random();
int[] arr = new int[10000];
for (int i = 0; i < arr.length; i++) {
arr[i] = random.nextInt(10000);
}
return arr;
}
public static void check1() {
int[] arr1 = generateRandomArray();
int[] arr2 = new int[arr1.length];
System.arraycopy(arr1,0, arr2,0, arr2.length);
Arrays.sort(arr1);
InsertionSort.insertionSort(arr2);
boolean flag = true;
for (int i = 0; i < arr1.length; i++) {
if (arr1[i] != arr2[i]) {
flag = false;
break;
}
}
System.out.println(flag ? "right" : "wrong");
}
public static void check2() {
int[] arr1 = generateRandomArray();
int[] arr2 = new int[arr1.length];
System.arraycopy(arr1,0, arr2,0, arr2.length);
Arrays.sort(arr1);
InsertionSortOpt1.insertionSortOpt(arr2);
boolean flag = true;
for (int i = 0; i < arr1.length; i++) {
if (arr1[i] != arr2[i]) {
flag = false;
break;
}
}
System.out.println(flag ? "right" : "wrong");
}
public static void check3() {
int[] arr1 = generateRandomArray();
int[] arr2 = new int[arr1.length];
System.arraycopy(arr1,0, arr2,0, arr2.length);
Arrays.sort(arr1);
InsertionSortOpt2.insertionSortOpt(arr2);
boolean flag = true;
for (int i = 0; i < arr1.length; i++) {
if (arr1[i] != arr2[i]) {
flag = false;
break;
}
}
System.out.println(flag ? "right" : "wrong");
}
public static void main(String[] args) {
check1();
check2();
check3();
}
}
样例输出
时间复杂度
一般情况下,两次循环,每一次排序都需要将未排序的元素逐一插入到已排序的部分中,需要比较 n-1 次才能获得排序后的结果。时间复杂度为n^2
最好情况下,将未排序的元素直接插入到已排序的部分中,不需要进行过多的比较和移动操作,因此插入排序的最好情况下的时间复杂度为 O(n)。
稳定性
它只会交换相邻的两个元素,以保证排序后的结果不变,算法稳定。