插入排序
直接插入排序
将待排序序列分为有序区和无序区,将无序区的元素逐一插入到有序区合适的位置上,直到全部有序。
类似玩牌时整理排的过程。
直接插入排序步骤
1.以数组第一个元素为有序区。
2.将无序区的第一个元素关键码,插入到有序区。
- 寻找关键码在有序区的目标位置
- 插入关键码
重复步骤2,直至全部有序。
直接插入排序演示:
算法分析
直接插入排序-java实现
/** * 直接插入排序的分步理解 * * @param arr */ public static void straightInsertionSort_step(int[] arr) { int size = arr.length; for (int i = 1; i < size; i++) { // arr[i]为关键码 int destIndex = 0; // 插入的目标下标 int key = arr[i]; // 保存关键码 // 遍历寻找destIndex for (int j = i - 1; j >= 0; j--) { if (arr[j] <= key) { // 如果关键码>=序区元素j,则插入j之后,否则,插入0下标 destIndex = j + 1; break; } } // 后移记录 for (int j = i - 1; j >= destIndex; j--) {// 从前向后会覆盖 arr[j + 1] = arr[j]; } // 插入 arr[destIndex] = key; System.out.print("第 " + i + "轮 :" + Arrays.toString(arr)); System.out.println("\tdestIndex:" + destIndex); } } /** * 直接插入排序 * * @param arr */ public static void straightInsertionSort(int[] arr) { int size = arr.length; for (int i = 1; i < size; i++) { // 外层控制轮数 int key = arr[i]; // arr[i]为关键码 int j = i - 1; for (; j >= 0 && key < arr[j]; j--){ //如果关键码>=序区元素j,则插入j之 arr[j + 1] = arr[j]; // 在寻找关键码插入位置的同时将元素后移 } arr[j + 1] = key; // 插入目标位置 System.out.print("第 " + i + "轮 :" + Arrays.toString(arr)); System.out.println("\tdestIndex:" + (j + 1)); } }
希尔排序
希尔排序是对直接插入排序的一种改进,着眼于:
- 若排序记录按关键码基本有序,直接插入排序的效率很高;
- 记录个数少,直接插入排序效率高。因为直接插入排序时间复杂度为O(n^2),n越小,效率越高。
希尔排序思想:
- 把记录按步长 gap 分组,对每组记录采用直接插入排序方法进行排序。保证整个序列基本有序。
- 随着步长逐渐减小,所分成的序列包含的记录越来越多,当步长的值减小到 1 时,所有记录合成为一组,经过直接插入排序后,构成一组有序记录,则完成排序。
开始时增量的取值较大,每个子序列记录个数少,排序效率较高;后来增量逐步缩小,每个子序列中的记录个数增加,但已经基本有序,故排序效率也较高。
希尔排序演示:
算法分析
希尔排序-java实现
/** * “把记录按步长 gap分组,对每组记录采用直接插入排序方法进行排序。保证整个序列基本有序.”<br> * @param arr */ public static void shellSort(int[] arr) { int size = arr.length; //把下标增量为gap的记录编为一个子序列 //增量逐步减小,直到整个序列的子序列为本身,即增量gap=1 for (int gap = size / 2; gap >= 1; gap /= 2) { //对子序列进行直接插入排序 for (int i = gap; i < size; i++) { int key = arr[i]; int j = i - gap; for (; j >= 0 && key < arr[j]; j -= gap) { arr[j + gap] = arr[j]; } arr[j + gap] = key; } System.out.println("gap: " + gap + " :" + Arrays.toString(arr)); } }