排序算法——插入排序

基本思想:

通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应的位置并插入。

 

算法描述:

以n个数升序排序为例,从第2个元素开始遍历,到最后一个数结束,共遍历(n-1)轮,对与第i轮:

将元素设为target与第(i-1)个元素比较,若target小于元素(i-1),则将元素(i-1)后移一位,

将target与元素(i-2)比较,若target小于元素(i-2),则将元素(i-2)后移一位,

......

如此类推,直到target大于某个元素,则将target插入该元素后的空位中,

已经遍历到队头也没有比target小的数,则把target插入队头。

可以看出,对于第i轮遍历,前(i-1)个元素是有序的。

另外为什么要强调从后向前比较,如果从前向后比较,找到正确位置后,需要将该位置后的所有元素(包括有序的和未排序的)后移一位,效率感人;

从已排序序列从后向前遍历,首先,抽起的target遗留了一个空位,利用这个空位,后边未排序的元素不必后移,移动的元素减少了,

其次,遍历的时候同时作比较位移两个操作,而非先遍历一次找到位置,再遍历一次移动元素,效率自然就更高了。

 

Java代码实现:

 1 /**
 2  * 用插入排序算法对整型数组进行升序排序
 3  *
 4  * @param arr:待排序数组
 5  */
 6 private static void insertSort(int[] arr) {
 7     if (arr == null || arr.length <= 1)
 8         return;
 9     for (int i = 1; i < arr.length; i++) { //从第2个元素开始遍历
10         int target = arr[i];
11         int j = i;
12         while (j > 0 && target < arr[j - 1]) { //遍历直到队头或找到比target小的元素
13             arr[j] = arr[j - 1]; //将arr[j-1]后移一位
14             j--;
15         }
16         arr[j] = target; //将target插入到正确位置
17     }
18 }

 

特点:

1. 插入排序平均时间复杂度是O(N2),情况最好时(全部已排序)为O(N),情况最坏时(全部反序)为O(N2)。

2. 插入排序是稳定的排序算法。

 

优化:

二分插入排序,又叫折半插入排序,是对直接插入排序的一种优化。

二分插入排序插入时不再是从后往前遍历,而是对已有序的元素做二分查找操作,找到正确位置。

当元素比较多时,总比较次数比直接插入排序的最差情况好得多,但比最好情况要。元素基本有序时,直接插入排序比二分插入排序比较次数少。

二分插入排序元素移动次数与直接插入排序相同

二分插入排序的平均时间复杂度是O(N2),情况最好时是O(logN),情况最坏时是O(N2)。二分插入排序是稳定的排序算法。

 

 1 /**
 2  * 用二分插入排序算法对整型数组进行升序排序
 3  *
 4  * @param arr:待排序数组
 5  */
 6 private static void binaryInsertSort(int[] arr) {
 7     if (arr == null || arr.length <= 1)
 8         return;
 9     for (int i = 1; i < arr.length; i++) {
10         int target = arr[i];
11         int insertIndex = findInsertIndex(arr, i - 1, target);
12         //如果待插入位置就是当前位置,则不必作后移操作,直接跳过
13         if (i == insertIndex)
14             continue;
15         //从有序元素的最后一个元素开始,作后移操作,到待插入位置的元素后移后结束
16         for (int j = i - 1; j >= insertIndex; j--)
17             arr[j + 1] = arr[j];
18         //将待插入元素插入正确位置
19         arr[insertIndex] = target;
20     }
21 }
22 
23 /**
24  * 用二分查找算法,找到二分插入排序算法中,待插入元素的正确位置
25  *
26  * @param arr:待排序数组
27  * @param maxIndex:已有序元素的最大下标
28  * @param target:待插入元素
29  * @return 待插入元素的正确位置
30  */
31 private static int findInsertIndex(int[] arr, int maxIndex, int target) {
32     int low = 0;
33     int high = maxIndex;
34     while (low <= high) {
35         int mid = (low + high) / 2;
36         if (arr[mid] > target)
37             high = mid - 1;
38         else
39             low = mid + 1;
40     }
41     return low;
42 }

 

posted @ 2017-09-12 01:28  LW_FUNG  阅读(208)  评论(0)    收藏  举报