JAVA算法——排序之归并排序

JAVA算法——排序之归并排序

以下内容为学习之后整理的内容。参考其它优秀文章,结合自己的理解,规整之后成文。可以作为自己的学习笔记

归并排序是一种基于“分治”策略的一种算法。归并排序算法是典型的分治算法,对于规模较大的问题,可以分解成若干容易求解的简单的问题,最后把解合并构成初始问题的解。

1 合并两个有序数组

这个非常简单,只要从比较二个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。

void mergeArray1(int[] a,int[] b){
    int lenA=a.length;
    int lenB=b.length;
    int i=0,j=0,k=0;
    int[] c=new int[lenA+lenB];
    while(i<lenA && j<lenB){
        if(a[i]<b[j]){
            c[k++]=a[i++];
        }else{
            c[k++]=b[j++];
        }
    }
    while(i<lenA){
        c[k++]=a[i++];
    }
    while(k<lenB){
        c[k++]=b[j++];
    }
}

由算法可以看出合并两个有序数列的时间复杂度为:O(n)。

2 归并排序

归并排序,其的基本思路就是将数组分成二组A,B,如果这二组组内的数据都是有序的,那么就可以很方便的将这二组数据进行排序。

如何让这二组组内数据有序了?

可以将A,B组各自再分成二组。依次类推,当分出来的小组只有一个数据时,可以认为这个小组组内已经达到了有序,然后再合并相邻的二个小组就可以了。这样通过先递归的分解数列,再合并数列就完成了归并排序。

即归并排序分为两个步骤:分解和合并

2.1 原理

(1)申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
(2)设定两个指针,最初位置分别为两个已经排序序列的起始位置
(3)比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
(4)重复步骤3直到某一指针达到序列尾
(5)将另一序列剩下的所有元素直接复制到合并序列尾

2.2 时间复杂度

“归并排序”利用了完全二叉树的深度是log2n+1(即以2为底N的对数下取整(下取整是指比如9.2点,上取整就是10,下取整就是9了),然后再+1),因此效率比较高。

一趟归并需要将数组 a[]中相邻的长度为h的有序序列进行两两归并.并将结果放到temp[]中,这需要将待排序列中的所有记录扫描一遍,因此耗费O(n),而又完全二叉树的深度可知,整个归并排序需要进行log2n次(以2为底N的对数),因此总的时间复杂度为O(nlogn),而且这是归并排序算法中最好、最坏、平均的时间性能。

2.3 空间复杂度

归并排序在归并过程中需要与原始序列同样数量的存储空间存放归并结果以及递归时深度为log2n(以2为底N的对数)的栈空间,因此空间复杂度为O(n+logn).

归并排序是一种比较占内存,但却效率高且稳定的算法。

2.4 Java算法实现

public class MergeSort {

    public static void merge(int[] a, int low, int mid, int high) {
        int[] temp = new int[high - low + 1];
        int i = low;// 左指针
        int j = mid + 1;// 右指针
        int k = 0;
        // 把较小的数先移到新数组中
        while (i <= mid && j <= high) {
            if (a[i] < a[j]) {
                temp[k++] = a[i++];
            } else {
                temp[k++] = a[j++];
            }
        }
        // 把左边剩余的数移入数组
        while (i <= mid) {
            temp[k++] = a[i++];
        }
        // 把右边边剩余的数移入数组
        while (j <= high) {
            temp[k++] = a[j++];
        }
        // 把新数组中的数覆盖nums数组
        for (int k2 = 0; k2 < temp.length; k2++) {
            a[k2 + low] = temp[k2];
        }
    }

    public static void mergeSort(int[] a, int low, int high) {
        int mid = (low + high) / 2;
        if (low < high) {
            // 左边
            mergeSort(a, low, mid);
            // 右边
            mergeSort(a, mid + 1, high);
            // 左右归并
            merge(a, low, mid, high);
            System.out.println(Arrays.toString(a));
        }

    }

    public static void main(String[] args) {
        int a[] = { 51, 46, 20, 18, 65, 97, 82, 30, 77, 50 };
        mergeSort(a, 0, a.length - 1);
        System.out.println("排序结果:" + Arrays.toString(a));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值