3、折半插入排序BinInsertSort

1、对直接插入排序的优化

上一次我们说插入排序是将第i个元素插入到前i-1个有序数组的合适位置。直接插入的时候是通过不断比较和交换元素来找到这样的一个位置,而折半插入排序通过二分有序数组来确定插入位置,从而减少比较次数。

2、代码实现

public class BinInsertSort {

  /**
   * @param arr
   *          要排序的数组
   * @return 排序后的数组
   */
  public static Integer[] sort(Integer[] arr) {
    return sort(arr, 0, arr.length - 1);
  }

  public static Integer[] sort(Integer[] arr, int left, int right) {
    for (int i = left + 1; i <= right; i++) {
      // 当前需要进行排序的元素
      Integer temp = arr[i];
      // 需要比较的条件
      if (arr[i - 1] > arr[i]) {
        int low = left, high = i - 1;
        while (low <= high) {
          int mid = (low + high) / 2;
          if (arr[mid] < temp) {
            low = mid + 1;
          } else {
            high = mid - 1;
          }
        }
        // 找到合适的位置,进行元素的移动操作
        for (int j = i - 1; j > high; j--) {
          arr[j + 1] = arr[j];
        }
        arr[high + 1] = temp;
      }
    }
    return arr;
  }
}

折半插入排序所需的辅助空间与直接插入排序相同,从时间上比较,折半插入排序仅减少了元素的比较次数,但是并没有减少元素的移动次数,因此折半插入排序的时间复杂度仍为O(n^2)。

3、单元测试

  /**
   * 测试折半查找插入排序
   */
  @Test
  public void testBinInsertSort() {
    int n = 10;
    Integer[] arr = SortHelper.generateRandomArray(n, 0, 50);
    SortHelper.printArr("排序前数组:", arr);
    SortHelper.testSort(BinInsertSort.class.getName(), "sort", arr, true);
    
    // 排序前数组:
    // 29,15,32,23,7,32,28,39,28,4
    // 排序后数组:
    // 4,7,15,23,28,28,29,32,32,39
  }
  /**
   * 测试选择排序、直接插入排序、折半插入排序
   */
  @Test
  public void testSIBSort() {
    int n = 20000;
    Integer[] arr = SortHelper.generateRandomArray(n, 0, 100000);// 几乎无序
    Integer[] arr1 = SortHelper.generateNearlyOrderedArray(n, 100);// 近乎有序
    Integer[] arr2 = SortHelper.generateRandomArray(n, 0, 10);// 存在大量重复数据

    Integer[] insertSortArr = Arrays.copyOf(arr, arr.length);
    Integer[] insertSortArr1 = Arrays.copyOf(arr1, arr.length);
    Integer[] insertSortArr2 = Arrays.copyOf(arr2, arr.length);

    Integer[] binInsertSortArr = Arrays.copyOf(arr, arr.length);
    Integer[] binInsertSortArr1 = Arrays.copyOf(arr1, arr.length);
    Integer[] binInsertSortArr2 = Arrays.copyOf(arr2, arr.length);

    System.out.println("选择排序:");
    SortHelper.testSort(SelectionSort.class.getName(), "sort", arr);
    SortHelper.testSort(SelectionSort.class.getName(), "sort", arr1);
    SortHelper.testSort(SelectionSort.class.getName(), "sort", arr2);
    System.out.println("直接插入排序:");
    SortHelper.testSort(InsertSort.class.getName(), "sort", insertSortArr);
    SortHelper.testSort(InsertSort.class.getName(), "sort", insertSortArr1);
    SortHelper.testSort(InsertSort.class.getName(), "sort", insertSortArr2);
    System.out.println("折半插入排序:");
    SortHelper.testSort(InsertSort.class.getName(), "binInsertSort", binInsertSortArr);
    SortHelper.testSort(InsertSort.class.getName(), "binInsertSort", binInsertSortArr1);
    SortHelper.testSort(InsertSort.class.getName(), "binInsertSort", binInsertSortArr2);
    
    // 选择排序:
    // SelectionSort->sort用时: 336ms
    // SelectionSort->sort用时: 308ms
    // SelectionSort->sort用时: 266ms
    // 直接插入排序:
    // InsertSort->sort用时: 549ms
    // InsertSort->sort用时: 7ms
    // InsertSort->sort用时: 369ms
    // 折半插入排序:
    // InsertSort->binInsertSort用时: 369ms
    // InsertSort->binInsertSort用时: 7ms
    // InsertSort->binInsertSort用时: 331ms
  }

(1)对于近乎有序的情况,直接插入排序和折半插入排序的时间效率远远大于选择排序;

(2)对于几乎无序或者存在大量重复的数组,选择排序由于插入排序;

(3)折半插入排序的时间效率高于直接插入排序。

转载于:https://my.oschina.net/u/3550572/blog/988563

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值