【排序基础】5、插入排序法 - Insertion Sort
插入排序法 - Insertion Sort
简单记录-bobo老师的玩转算法系列–玩转算法 -排序基础
插入排序 Insertion Sort
比较 插入
插入排序设计思想
插入排序将数列划分为“已排序的”和“未排序的”两部分,每次从“未排序的”元素中选择一个插入到“已排序的”元素中的正确位置,如此迭代直到全部元素有序。
一般将将数组的第一个数认为是有序数组,第一个数不需要考虑 已经排好了,不需要插入到前面去。从后往前扫描该有序数组,把数组中其余n-1个数,根据数值的大小,插入到有序数组中,直至数组中的所有数为有序数组为止。n个元素的话就需要进行n-1趟排序!比较 插入。
例如:1 2 3 4进行从大到小的排序
第一趟
1 2 3 4
从后往前扫描有序数组,将第二个数字2和有序数组中的1进行比较,2大于1,所以将1后移一个位置,正好此时也是扫描完该有序数组中所以的数,所以结果是将2插入到1的前面,得到新的序列2,1;
2 1 3 4
第二趟
2 1 3 4
3开始,3比1大,1后移一个位置,就是这两个交换一下位置
2 3 1 4
3比2大,2后移一个位置。
3 2 1 4
第三趟
3 2 1 4
4开始,4比1大,1后移一个位置
3 2 4 1
4比2大,2后移一个位置
3 4 2 1
4比3大,3后移,比完了
4 3 2 1
插入排序代码实现
InsertionSort
package algo;
import java.util.*;
public class InsertionSort{
// 我们的算法类不允许产生任何实例
private InsertionSort(){}
public static void sort(Comparable[] arr){
int n = arr.length;
for (int i = 0; i < n; i++) {
// 寻找元素arr[i]合适的插入位置
// 写法1
// 比较 当前与它的前一个 小于的话就交换 大的话就中止这一趟
// 插入排序比选择 第二个循环比较 提前中止 理论上插入比选择快点 但是...实际上为什么更慢呢?下一节介绍可以改进吧
// for( int j = i ; j > 0 ; j -- )
// if( arr[j].compareTo( arr[j-1] ) < 0 )
// swap( arr, j , j-1 );
// else
// break;
// 写法2
//同时满足两个 j > 0 小于的话就一直交换 一旦大于就中止 下一个数进行比较
for( int j = i; j > 0 && arr[j].compareTo(arr[j-1]) < 0 ; j--)
swap(arr, j, j-1);
}
}
private static void swap(Object[] arr, int i, int j) {
Object t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
// 测试InsertionSort
public static void main(String[] args) {
int N = 200;
Integer[] arr = SortTestHelper.generateRandomArray(N, 0, 10000);
SortTestHelper.testSort("algo.InsertionSort", arr);
return;
}
}
SortTestHelper.java
package algo;
import java.lang.reflect.Method;
import java.lang.Class;
public class SortTestHelper {
// SortTestHelper不允许产生任何实例
private SortTestHelper(){}
// 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR]
public static Integer[] generateRandomArray(int n, int rangeL, int rangeR) {
assert rangeL <= rangeR;
Integer[] arr = new Integer[n];
for (int i = 0; i < n; i++)
arr[i] = new Integer((int)(Math.random() * (rangeR - rangeL + 1) + rangeL));
return arr;
}
// 打印arr数组的所有内容
public static void printArray(Object[] arr) {
for (int i = 0; i < arr.length; i++){
System.out.print( arr[i] );
System.out.print( ' ' );
}
System.out.println();
return;
}
// 判断arr数组是否有序
public static boolean isSorted(Comparable[] arr){
for( int i = 0 ; i < arr.length - 1 ; i ++ )
if( arr[i].compareTo(arr[i+1]) > 0 )
return false;
return true;
}
// 测试sortClassName所对应的排序算法排序arr数组所得到结果的正确性和算法运行时间
public static void testSort(String sortClassName, Comparable[] arr){
// 通过Java的反射机制,通过排序的类名,运行排序函数
try{
// 通过sortClassName获得排序函数的Class对象
Class sortClass = Class.forName(sortClassName);
// 通过排序函数的Class对象获得排序方法
Method sortMethod = sortClass.getMethod("sort",new Class[]{Comparable[].class});
// 排序参数只有一个,是可比较数组arr
Object[] params = new Object[]{arr};
long startTime = System.currentTimeMillis();
// 调用排序函数
sortMethod.invoke(null,params);
long endTime = System.currentTimeMillis();
assert isSorted( arr );
System.out.println( sortClass.getSimpleName()+ " : " + (endTime-startTime) + "ms" );
}
catch(Exception e){
e.printStackTrace();
}
}
}
Result 测试 InsertionSort
D:\Environments\jdk-11.0.2\bin\java.exe -javaagent:D:\Java\ideaIU-2019.2.win\lib\idea_rt.jar=7391:D:\Java\ideaIU-2019.2.win\bin -Dfile.encoding=UTF-8 -classpath D:\IdeaProjects\imooc\Play-with-Algorithms\02-Sorting-Basic\out\production\05-Insertion-Sort algo.InsertionSort
InsertionSort : 2ms
48 68 73 256 393 415 512 520 521 549 558 613 618 650 707 709 720 755 813 830 841 853 856 894 1017 1061 1092 1199 1212 1227 1374 1421 1454 1535 1552 1584 1601 1617 1652 1758 1907 1979 1998 2081 2103 2107 2157 2246 2271 2274 2312 2319 2365 2418 2449 2509 2565 2569 2629 2668 2741 2793 2927 2950 2956 3105 3140 3166 3209 3287 3364 3403 3407 3427 3469 3573 3645 3835 3887 3902 3919 4045 4071 4122 4225 4300 4355 4364 4378 4412 4505 4516 4523 4533 4546 4636 4650 4678 4776 4780 4821 4911 5010 5174 5204 5220 5231 5426 5473 5484 5645 5827 5884 5887 5902 5939 6012 6031 6063 6174 6210 6334 6337 6358 6358 6367 6405 6412 6448 6639 6678 6838 6991 7002 7148 7189 7327 7357 7400 7429 7519 7522 7559 7634 7733 7841 7945 7960 8013 8116 8139 8193 8203 8214 8222 8234 8243 8248 8258 8273 8309 8357 8452 8569 8586 8662 8687 8740 8842 8853 8863 8891 8907 8930 8950 9011 9086 9148 9239 9251 9286 9321 9346 9392 9434 9491 9518 9537 9589 9601 9675 9766 9801 9825 9837 9882 9883 9884 9915 9962
Process finished with exit code 0
操作:插入排序与选择排序的比较
Main
package algo;
import java.util.Arrays;
public class Main {
// 比较SelectionSort和InsertionSort两种排序算法的性能效率
// 此时,插入排序比选择排序性能略低
public static void main(String[] args) {
int N = 200000;//20万个数排序
System.out.println("Test for random array, size = " + N + " , random range [0, " + N + "]");
Integer[] arr1 = SortTestHelper.generateRandomArray(N, 0, N);
Integer[] arr2 = Arrays.copyOf(arr1, arr1.length);//拷贝数组
SortTestHelper.testSort("algo.SelectionSort", arr1);
SortTestHelper.testSort("algo.InsertionSort", arr2);
return;
}
}
选择 插入排序 性能不行 数据集合一大点 就很慢很慢了
比较 交换 次数太多了
Result
D:\Environments\jdk-11.0.2\bin\java.exe -javaagent:D:\Java\ideaIU-2019.2.win\lib\idea_rt.jar=7405:D:\Java\ideaIU-2019.2.win\bin -Dfile.encoding=UTF-8 -classpath D:\IdeaProjects\imooc\Play-with-Algorithms\02-Sorting-Basic\out\production\05-Insertion-Sort algo.Main
Test for random array, size = 200000 , random range [0, 200000]
SelectionSort : 87513ms
InsertionSort : 335960ms
Process finished with exit code 0