排序算法之归并排序(二路归并)

归并排序算法的中心思想:先拆分-再合并。


具体思路:

先拆分:将数组从中间一分为二,形成两个左、右两个数组。再次分别递归左、右两个数组,重复此步骤(递归进行),直至数组中剩下的元素只有一个。(左右为代称,每一次的左、右数组实际都为两个新的数组。)

再合并:当左数组中只剩一个元素时,递归返回,右数组同样也只剩下一个元素,调用合并方法,将这两个元素合并为有序序列。此时返回上一层递归,再次合并一个有序序列,再将这两个有序序列进行合并。重复此步骤,最终合并成为一个大的有序序列。

代码实现:
public class Test {
/**
 * 拆分操作:将原数组在中间拆分开,形成左右数组,再次重复此过程,直到跳出递归,既此时的左数组中只含有一个元素,返回上一层递归
 * 右数组执行递归,同样跳出递归时只有一个元素,然后执行合并方法。
 */
private void mergeSort(int[] arr, int left, int right) {
    int mid = (left + right) >>> 1;
    if (left >= right)
        return;

    mergeSort(arr, left, mid);
    mergeSort(arr, mid + 1, right);
    merge(arr, left, mid, right);
}
/**
 * 合并操作:有三个参数,arr数组中至少有2个元素,left是当前数组元素的起始位置,mid是将arr数组拆分开的位置,right是数组中的结束位置
 */
private void merge(int[] arr, int left, int mid, int right) {
    //将arr拆分为两个归并段
    //第一个归并段的起始位置
    int start1 = left;
    //第二个归并段的起始位置
    int start2 = mid + 1;
    //临时数组,用来存放归并完成的元素,数组的长度是根据传进来的开始结束位置决定的
    int[] temp = new int[right - left + 1];
    //指向临时数组要存元素的位置
    int t = 0;

    //当起始位置<=末尾位置时,说明至少有一个元素。当有一个归并段没有元素了就会退出循环,但另一个归并段还有没有元素呢?
    while (start1 <= mid && start2 <= right) {
        //如果第一个归并段的元素<=第二个归并段的元素,将第一个归并段的元素放进临时数组中,下标都要+1,否则就把第二个归并段的元素放进去
        if (arr[start1] <= arr[start2]) {
            temp[t] = arr[start1];
            start1++;
            t++;
        } else {
            temp[t] = arr[start2];
            start2++;
            t++;
        }
    }

    //如果此时第一个归并段还有元素,直接把所有元素放到临时数组末尾
    while (start1 <= mid) {
        temp[t] = arr[start1];
        start1++;
        t++;
    }
    //如果此时第二个归并段还有元素,直接把所有元素放到临时数组末尾
    while (start2 <= right) {
        temp[t] = arr[start2];
        start2++;
        t++;
    }

    //将临时数组中的值取出来放进原数组中
    //但要注意,不是每一个归并段都是从下标0开始的,要注意归并段的原始下标
    for (int i = 0; i < temp.length; i++) {
        arr[i + left] = temp[i];
    }

}
public static void main(String[] args) {
    // int[] arr = new int[100000];
    // for (int i = 100000-1; i >= 0; i--) {
    //     arr[i] = i;
    // }
    int[] arr = {7,3,5,6,4,1,2,0};
    long start = System.currentTimeMillis();
    new Test().mergeSort(arr, 0, arr.length - 1);
    // for (int i : arr) {
    //     System.out.println(i);
    // }
    long end = System.currentTimeMillis();
    System.out.println(end - start);
}
}
 归并算法的时间复杂度:

归并排序的时间复杂度为O(nlogn),其中n是待排序数组的长度。归并排序的分治思想保证了每一次合并操作的时间复杂度都是O(n),而每一次递归都会把数组分成两个子数组,因此递归层数为logn。因此,归并排序的时间复杂度为O(nlogn)。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值