3-3 归并排序法的优化

3-3 归并排序法的优化

本节介绍上一节实现的归并排序的两个优化:

1、在 mergeOfTwoSortArray 对两个有序的数组进行归并的时候,如果两个数组合并之前就是有序的数组,就不用再复制来复制去的了;

2、在归并的子过程中,如果待排序的数组元素个数很少的情况下,可以使用插入排序,因为插入排序对于近乎有序的数组而言,可以提前终止循环,从而提高整体排序的效率

下面我们具体来说明:

1、归并排序写好以后,我们可以尝试将其与插入排序进行一个 5000 级别的数据排序的比较测试。

结论是显而易见的,因为插入排序的时间复杂度是 O(n^2),归并排序的时间复杂度是 O(nlogn)。所以,在绝大多数情况下,归并排序的性能较好,插入排序的效率较低

2、但是我们还要认识到一点,在待排序的数组在近乎有序的前提下,插入排序可以达到 O(n) 的时间复杂度,效果非常好;

3、归并(merge)排序的优化思路:

(1)事实上,当 arr[mid]<=arr[mid+1] 的时候是不用 merge 的,如图所示:

代码实现:

if (arr[mid] < arr[mid + 1]) {
    return;
}

(2)递归到底的时候,可以使用插入排序优化,例如在处理 16 个元素的数组时候,不用继续递归,此时使用插入排序提升性能。

“递归到底”这件事情可以由我们自己定义:

原来我们定义的递归到底这件事情是:当数组区间里只有一个元素的时候,这个元素就是有序的,所以递归不能再进行下去了。

现在我们定义的递归到底这件事情是:当数组区间里的元素是有限个的时候,我们改用插入排序法来完成排序。

代码实现:

if(right-left<=15){
    // 使用插入排序去排序这部分的数组元素
}

代码实现:

/**
 * 对数组给定的部分使用插入排序
 *
 * @param arr   给定数组
 * @param left  左边界,能取到
 * @param right 右边界,能取到
 */
private void insertSort(int[] arr, int left, int right) {
    for (int i = left + 1; i <= right; i++) { // 第 1 遍不用插入,所以是总长度减去 1
        int temp = arr[i];
        int j;
        for (j = i - 1; j > left; j--) {
            if (arr[j] > temp) { // 后移一位
                arr[j + 1] = arr[j];
            } else {
                break;
            }
        }
        arr[j] = temp;
    }
}

使用 15 是不是效果最优的呢?这是一个经验值。

下面编写测试用例:

/**
 * 测试归并排序及其性能优化
 */
@Test
public void test07() {
    int[] randomArray1 = SortTestHelper.generateRandomArray(1000000, 1, 500000000);
    int[] randomArray2 = SortTestHelper.copyFromOldArray(randomArray1);
    SortTestHelper.testSortEfficiency(new MergeSort(), randomArray1);
    SortTestHelper.testSortEfficiency(new MergeSortOptimize1(), randomArray2);
    SortTestHelper.testSorted(randomArray1);
    SortTestHelper.testSorted(randomArray2);
}

执行结果:

您所使用的排序算法是 => merge sort(归并排序)

排序算法耗时 => 0.181 秒

您所使用的排序算法是 => 归并排序性能优化1

排序算法耗时 => 0.101 秒

给定数组按照升序排序!

给定数组按照升序排序!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值