排序基础02:插入排序法
核心思想:从第二个元素开始依次和前面的元素进行比较,如果比前一个元素小,那就让前一个元素后移一位,继续向前遍历,直到前面所有的元素都比自己小,那就存在当前的位置。然后再从第三个元素开始...最终完成排序
实现插入排序法
import java.util.Arrays;
public class Algorithm {
public static void main(String[] args) {
Integer[] arr = {2, 5, 6, 8, 1, 3};
InsertionSortBetter.sort(arr);
System.out.println(Arrays.toString(arr));
}
}
class InsertionSortBetter {
private InsertionSortBetter() {}
public static <E extends Comparable> void sort(E[] arr) {
for (int i = 1; i < arr.length; i++) {
/**
* 循环不变量:arr[i...n)未排序,而arr[0...i)已排序
* 优化点:将arr[i]先暂存起来,从后向前依次和arr[0...i)中的元素进行对比,谁比它大谁就往后挪一位,直到前面的元素都比它小,然后将arr[i]放在j这个位置
*/
E tem = arr[i];
/**
* 因为j在后面还要用到,所以在for循环外面定义
*/
int j;
/**
* if()语句判断的条件只有一个,可以一同写进for()循环,省去了break语句的跳转,简化代码
*/
for (j = i; j - 1 >= 0 && tem.compareTo(arr[j - 1]) < 0; j--) {
arr[j] = arr[j - 1];
}
/**
* for循环结束时j会自动减1,此时j刚好是空位置的索引
*/
arr[j] = tem;
}
}
}
选择排序法和插入排序法性能比较
插入排序法的复杂度也是O(n^2)
但是和选择排序相比,当一个数组本身的有序程序很高的时候,插入排序可能只要将arr[i]和arr[i + 1]对比一次就可以结束内循环,此时插入排序法的复杂度会降到O(n);而选择排序却一定要遍历所有arr[i...n]所有的元素才能确保找到最小值
所以当数组的有序程度较高时,推荐使用插入排序
import java.util.Arrays;
import java.util.Random;
public class Algorithm {
public static void main(String[] args) {
Integer[] testScale = {10000, 100000};
for (Integer n : testScale) {
/**
* 测试随机数组排序性能
*/
Integer[] randomArr = ArrayGenerator.generatorRandomArray(n, n);
/**
* 测试有序数组排序性能
*/
Integer[] sortedArr = ArrayGenerator.generatorSortedArray(n);
/**
* Arrays.copyOf()方法复制数值的数值,为了测试更具有对比性
*/
Integer[] arr1 = Arrays.copyOf(randomArr, randomArr.length);
Integer[] arr2 = Arrays.copyOf(randomArr, randomArr.length);
Integer[] arr3 = Arrays.copyOf(sortedArr, sortedArr.length);
Integer[] arr4 = Arrays.copyOf(sortedArr, sortedArr.length);
System.out.println("测试随机数组排序性能");
System.out.println();
Verify.testTime("SelectionSort", arr1);
Verify.testTime("InsertionSort", arr2);
System.out.println();
System.out.println("测试有序数组排序性能");
System.out.println();
Verify.testTime("SelectionSort", arr3);
Verify.testTime("InsertionSort", arr4);
System.out.println();
}
}
}
class InsertionSort {
private InsertionSort() {}
public static <E extends Comparable> void sort(E[] arr) {
for (int i = 1; i < arr.length; i++) {
E tem = arr[i];
int j;
for (j = i; j - 1 >= 0 && tem.compareTo(arr[j - 1]) < 0; j--) {
arr[j] = arr[j - 1];
}
arr[j] = tem;
}
}
}
class SelectionSort {
private SelectionSort(){}
public static<E extends Comparable<E>> void sort(E[] arr){
for (int i = 0; i < arr.length - 1; i++) {
int minIndex = i;
for (int j = i + 1; j < arr.length; j++) {
if (arr[j].compareTo(arr[minIndex]) < 0) {
minIndex = j;
}
}
if (i != minIndex) {
E tem;
tem = arr[minIndex];
arr[minIndex] = arr[i];
arr[i] = tem;
}
}
}
}
/**
* 生成随机数组和有序数组
*/
class ArrayGenerator {
private ArrayGenerator (){}
public static Integer[] generatorRandomArray (Integer n, Integer maxBound){
Integer[] arr = new Integer[n];
/**
* 创建Random类对象
*/
Random random = new Random();
for (int i = 0; i < n; i++) {
/**
* random.nextInt()方法随机生成整数
*/
arr[i] = random.nextInt(maxBound);
}
return arr;
}
public static Integer[] generatorSortedArray (Integer n){
Integer[] arr = new Integer[n];
for (int i = 0; i < n; i++) {
arr[i] = i;
}
return arr;
}
}
/**
* 先判断算法是否正确排序,再测试算法的执行时间
*/
class Verify {
private Verify (){}
public static<E extends Comparable<E>> boolean isSorted(E[] arr){
for (int i = 0; i < arr.length - 1; i++) {
if (arr[i].compareTo(arr[i + 1]) > 0) {
return false;
}
}
return true;
}
public static<E extends Comparable<E>> void testTime(String AlgorithmName, E[] arr) {
long startTime = System.nanoTime();
if (AlgorithmName.equals("SelectionSort")){
SelectionSort.sort(arr);
}
if (AlgorithmName.equals("InsertionSort")) {
InsertionSort.sort(arr);
}
long endTime = System.nanoTime();
if (!Verify.isSorted(arr)){
throw new RuntimeException(AlgorithmName + "算法排序失败!");
}
System.out.println(String.format("%s算法,测试用例为%d,执行时间:%f秒", AlgorithmName, arr.length, (endTime - startTime) / 1000000000.0));
}
}

浙公网安备 33010602011771号