1. 折半插入排序是对直接插入排序算法的改进,在直接插入排序算法中,不难看出每趟插入的过程中,都进行了两项工作:(1)从前面的有序子表中查找出待插入元素应该被插入的位置;(2)给插入位置腾出空间,将待插入元素复制到表中的插入位置。注意到该算法中,总是边比较边移动元素,下面将比较和移动操作分离出来,即先折半查找出元素的待插入位置,然后再统一地移动待插入位置之后的所有元素。当排序表为顺序存储的线性表时,可以对直接插入排序算法作如下改进:在查找子表时可以折半查找待插入元素的位置。在确定出待插入位置后,就可以统一地向后移动元素了。
2. 折半插入代码实现
1 package cn.sun.it.review; 2 3 import java.util.Arrays; 4 import java.util.Scanner; 5 6 public class BinaryInsertSort { 7 8 public static void main(String[] args) { 9 // 测试数据:5,3,6,2,1,9,4,8,7 10 System.out.println("请输入若干个整数,以逗号分隔:"); 11 Scanner sc = new Scanner(System.in); 12 String strNums = sc.nextLine(); 13 String[] tempArrNums = strNums.split(","); 14 int[] arr = new int[tempArrNums.length]; 15 for (int i = 0; i < arr.length; i++) { 16 arr[i] = Integer.valueOf(tempArrNums[i]); 17 } 18 System.out.println("排序前:" + Arrays.toString(arr)); 19 binaryInsertSort(arr); 20 System.out.println("排序后:" + Arrays.toString(arr)); 21 } 22 23 private static void binaryInsertSort(int[] arr) { 24 int temp; 25 for (int i = 1; i < arr.length; i++) { 26 if (arr[i] < arr[i - 1]) { 27 // 缓存i处元素的值 28 temp = arr[i]; 29 // 记录搜索范围的左边界 30 int low = 0; 31 // 记录搜索范围的右边界 32 int high = i - 1; 33 while (low <= high) { 34 // 记录中间位置 35 int mid = (low + high) / 2; 36 // 比较有序子表中间位置数据和i处数据的大小,以缩小搜索范围 37 if(arr[mid] < temp){ 38 low = mid+1; 39 }else{ 40 high = mid-1; 41 } 42 } 43 // 将low ~ i处的数据整体向后移动1位 44 for(int j=i;j>low;j--){ 45 arr[j] = arr[j-1]; 46 } 47 arr[low] = temp; 48 } 49 } 50 } 51 52 }
3. 折半插入排序性能
(3.1) 折半插入排序仅仅是减少了比较元素的次数,约为O(nlog2n),该比较次数与待排序表的初始状态无关,仅取决于表中的元素个数n;
(3.2)而元素的移动次数没有改变,它依赖于待排序表的初始状态。其时间复杂度仍为O(n2)
(3.3)折半插入排序是一个稳定的排序算法