image.png

  • arr[i…n)未排序, arr[0…i) 已排序 => 循环不变量 和选择排序法一致
  • 进步:有序的集合+1,无序的集合-1
  • 把arr[i]放到合适的位置

image.pngimage.png
image.png


选择排序法与插入排序法的区别

image.png

插入排序的特性

  • 内层循环能够提前终止
  • 对于有序数组,插入排序不会真正去移动元素,只会比较与前面的元素比较一次,然后发现不需要移动。这种情况,时间复杂度就会由O(n^2)变成O(n)
  • 对于基本有序的数组,使用插入排序是更好的选择,大部分内层循环都会直接跳过

image.png


插入排序的优化

  • 不再依次向前面交换,而是使用临时变量缓存arr[i]的值,这样每一位都只移动一次;
  • 时间复杂度没改变,是常数级别的优化。

image.png
image.png

优化后的结果

image.png

  1. public class InsertSort {
  2. private InsertSort() {
  3. }
  4. private static <E extends Comparable<E>> void sort(E[] arr) {
  5. for (int i = 0; i < arr.length; i++) {
  6. //将arr[i]插入到合适的位置
  7. for (int j = i; j - 1 >= 0 ; j--) {
  8. //依次当前值是否比前一个位置的值小,如果小就交换位置
  9. if (arr[j].compareTo(arr[j - 1]) < 0) {
  10. swap(arr, j, j - 1);
  11. } else {
  12. break;
  13. }
  14. }
  15. }
  16. }
  17. private static <E extends Comparable<E>> void sort2(E[] arr) {
  18. //插入排序的优化
  19. // 临时变量缓存,就只用移动一次,不再依次向前交换了
  20. for (int i = 0; i < arr.length; i++) {
  21. //将arr[i]插入到合适的位置
  22. E temp = arr[i];
  23. int j;
  24. for (j = i; j - 1 >= 0 && temp.compareTo(arr[j - 1]) < 0; j--) {
  25. arr[j] = arr[j - 1];
  26. }
  27. arr[j] = temp;
  28. }
  29. }
  30. private static <E> void swap(E[] arr, int i, int j) {
  31. E temp = arr[i];
  32. arr[i] = arr[j];
  33. arr[j] = temp;
  34. }
  35. public static void main(String[] args) {
  36. int[] dataSize = {10000,100000};
  37. for (int n : dataSize) {
  38. Integer[] data = ArrayGenerator.generateRandomArray(n,n);
  39. Integer[] data2 = Arrays.copyOf(data, data.length);
  40. SortingHelper.sortTest(InsertSort.class, "sort", data);
  41. SortingHelper.sortTest(InsertSort.class, "sort2", data2);
  42. }
  43. }
  44. }