直接插入排序
2015-05-17 19:18
169 查看
直接插入排序(Straight Insertion Sort)
基本思想:
先把要排序的数组分成两部分,第一部分只包含第一个元素,天然有序,而第二部分则包含了数组中除开第一个元素剩余的所有元素。然后依次将第二部分中的每一个元素插入到已经有序的第一部分中,并且仍保持第一部分有序。每次插入一个元素,有序部分将增加一个元素。
重复此过程,直到最后有序部分包含所有元素。
当然,有序部分也可以是最后一个元素。
好了,话不多说,上图。
初始数组如下:
![](https://img-blog.csdn.net/20150518154602374?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMDUxMjYwNw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
第一步:进行划分。第一个元素 4 为初始有序部分,其余元素为无序部分。即红线左边为有序部分,右边为无序部分。
![](https://img-blog.csdn.net/20150518154659564?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMDUxMjYwNw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
第二步:从无序部分的元素中依次找出一个元素插入到左边,并且保持插入后仍然有序。这里先将元素 2 插入到左边的有序部分。
![](https://img-blog.csdn.net/20150518154640887?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMDUxMjYwNw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
<第一次插入> 2
< 4,因此将 2 插入到 4 的左边
此时,有序部分变成了 2、4, 接着,
第三步:将元素 3 插入到左边,并且保持插入后仍然有序。
![](https://img-blog.csdn.net/20150518154747394?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMDUxMjYwNw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
<第二次插入> 3
< 4,3 > 2,因此将 3 插入到 2 和 4 的中间
此时,有序部分变成了 2、3、4, 继续,
第四步:将元素 5 插入到左边,并且保持插入后仍然有序。
![](https://img-blog.csdn.net/20150518154721743?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMDUxMjYwNw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
<第三次插入> 5
> 4,将 5 直接插入到 4 的右边
此时,左边的有序部分变成了 2、3、4、5, 接着
第五步:将元素 1 插入到左边,并且保持插入后仍然有序。
![](https://img-blog.csdn.net/20150518154749137?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMDUxMjYwNw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
<第四次插入> 1
< 5, 1 < 3, 1 < 2, 因此将 1 插入到 2 的左边
此时,所有元素都已经插入到了左边的有序部分,数组已经有序,排序结束。
其实,我们也看到了,插入排序的核心在于将无序部分元素插入到有序部分中,并且还得保持仍然有序。
就上边的情况来说,设定的是第一个元素为初始有序部分,余下元素为无序部分。其实,前面提到过,最后一个元素为初始有序部分也是可以的。完整的测试代码中包含了这种情况。
算法实现:
算法测试:
运行情况:
![](https://img-blog.csdn.net/20150517210115544?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMDUxMjYwNw==/font/5a6L5L2T/fontsize/400<br/>4000<br/>/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
基本思想:
先把要排序的数组分成两部分,第一部分只包含第一个元素,天然有序,而第二部分则包含了数组中除开第一个元素剩余的所有元素。然后依次将第二部分中的每一个元素插入到已经有序的第一部分中,并且仍保持第一部分有序。每次插入一个元素,有序部分将增加一个元素。
重复此过程,直到最后有序部分包含所有元素。
当然,有序部分也可以是最后一个元素。
好了,话不多说,上图。
初始数组如下:
第一步:进行划分。第一个元素 4 为初始有序部分,其余元素为无序部分。即红线左边为有序部分,右边为无序部分。
第二步:从无序部分的元素中依次找出一个元素插入到左边,并且保持插入后仍然有序。这里先将元素 2 插入到左边的有序部分。
<第一次插入> 2
< 4,因此将 2 插入到 4 的左边
此时,有序部分变成了 2、4, 接着,
第三步:将元素 3 插入到左边,并且保持插入后仍然有序。
<第二次插入> 3
< 4,3 > 2,因此将 3 插入到 2 和 4 的中间
此时,有序部分变成了 2、3、4, 继续,
第四步:将元素 5 插入到左边,并且保持插入后仍然有序。
<第三次插入> 5
> 4,将 5 直接插入到 4 的右边
此时,左边的有序部分变成了 2、3、4、5, 接着
第五步:将元素 1 插入到左边,并且保持插入后仍然有序。
<第四次插入> 1
< 5, 1 < 3, 1 < 2, 因此将 1 插入到 2 的左边
此时,所有元素都已经插入到了左边的有序部分,数组已经有序,排序结束。
其实,我们也看到了,插入排序的核心在于将无序部分元素插入到有序部分中,并且还得保持仍然有序。
就上边的情况来说,设定的是第一个元素为初始有序部分,余下元素为无序部分。其实,前面提到过,最后一个元素为初始有序部分也是可以的。完整的测试代码中包含了这种情况。
算法实现:
/** * 插入排序,最前一位作为有序部分 * @param arr 待排序数组 */ public void insertionSort(int[] arr) { int length = arr.length; int j = 0; int temp = 0; for (int i = 1; i < length; i++) { temp = arr[i]; // 存储待插入元素的值 for (j = i; j > 0; j--) { // 找到一个合适的插入位置 if (arr[j - 1] > temp) arr[j] = arr[j - 1]; // 依次向右移动已经排好序的元素,为待插入元素留出位置 else // 若后面的不小于前面的,则不用移动,因为前面的已经排好序了 break; } arr[j] = temp; // 将待插入元素插入到指定位置 } }
算法测试:
package algorithms; import java.util.Arrays; import java.util.Random; /** * 插入排序 * @author Wll * */ public class InsertionSortTest { public static void main(String[] args) { int[] arr = getRandomArray(9, 1000); int[] arr2 = Arrays.copyOf(arr, arr.length); System.out.println("插入排序"); System.out.print("初始数组:"); printArray(arr); System.out.println("第一位 " + arr[0] + " 为初始有序部分:"); insertionSort(arr); System.out.println(); System.out.println("最后一位 " + arr2[arr2.length - 1] + " 为初始有序部分:"); insertionSort2(arr2); } /** * 插入排序,最前一位作为有序部分 * @param arr 待排序数组 */ private static void insertionSort(int[] arr) { int length = arr.length; int j = 0; int temp = 0; for (int i = 1; i < length; i++) { temp = arr[i]; // 存储待插入元素的值 for (j = i; j > 0; j--) { // 找到一个合适的插入位置 if (arr[j - 1] > temp) arr[j] = arr[j - 1]; // 依次向右移动已经排好序的元素,为待插入元素留出位置 else // 若后面的不小于前面的,则不用移动,因为前面的已经排好序了 break; } arr[j] = temp; // 将待排序元素插入到指定位置 // 打印每一趟排序的结果 System.out.print("第" + i + "趟插入" + temp + ": "); for (int k = 0; k < length; k++) { if (k == (i + 1)) System.out.print("|"); // 使用|分隔有序和无序部分 if (k == j) System.out.print("▲"); // 为插入元素做标记 System.out.print(arr[k] + " "); } System.out.println("\n"); } } /** * 插入排序,最后一位作为有序部分 * @param arr 待排序数组 */ private static void insertionSort2(int[] arr) { int length = arr.length; int j = 0; int temp = 0; for (int i = length - 2; i >= 0; i--) { temp = arr[i]; for (j = i; j < length - 1; j++) { if (arr[j + 1] < temp) arr[j] = arr[j + 1]; else break; } arr[j] = temp; // 打印每一趟排序的结果 System.out.print("第" + (length - i - 1) + "趟插入" + temp + ": "); for (int k = 0; k < length; k++) { if (k == j) System.out.print("▲"); // 为插入元素做标记 System.out.print(arr[k] + " "); if (k == i-1) System.out.print("|"); // 使用|分隔有序和无序部分 } System.out.println("\n"); } } /** * 打印数组 * @param arr 待打印数组 */ private static void printArray(int[] arr) { int length = arr.length; for (int i = 0; i < length; i++) System.out.print(arr[i] + " "); System.out.println(); System.out.println(); } /** * 获得一个随机整型数组 * @param size 数组大小 * @param limit 数组元素大小的上限 * @return 一个随机数组 */ private static int[] getRandomArray(int size, int limit) { int[] arr = new int[size]; Random random = new Random(); for (int i = 0; i < size; i++) arr[i] = random.nextInt(limit); return arr; } }
运行情况: