归并排序算法(四)

一.归并排序
归并排序用到了分治思想,是将一个大问题分解成小的子问题来解决。小问题解决了,则大问题也就解决了。归并排序的核心思想:如果要排序一个数组,我们先把数组从中间分成前后两部分,然后对前后两部分分别排序,再将排好的两部分合并在一起,这样整个数组就都有序了。
在这里插入图片描述
参考文章
二,归并排序算法详细分析

归并排序算法有两个基本的操作,一个是分,也就是把原数组划分成两个子数组的过程。另一个是治,它将两个有序数组合并成一个更大的有序数组。

它将数组平均分成两部分: mid= (left + right)/2,当数组分得足够小时—数组中只有一个元素时,只有一个元素的数组自然而然地就可以视为是有序的,此时就可以进行合并操作了。因此,上面讲的合并两个有序的子数组,是从 只有一个元素 的两个子数组开始合并的。

比如初始数组:[24,13,26,1,2,27,38,15]

①分成了两个大小相等的子数组:[24,13,26,1] [2,27,38,15]

②再划分成了四个大小相等的子数组:[24,13] [26,1] [2,27] [38,15]

③此时,left < right 还是成立,再分:[24] [13] [26] [1] [2] [27] [38] [15]

此时,有8个小数组,每个数组都可以视为有序的数组了!!!,每个数组中的left == right,

merge([24],[13]) 得到 [13,24]

merge([26],[1]) 得到[1,26]

最终得到 有序数组。
代码实现1:

package data.Sort;

public class MergerSort {
    public static void main(String[] args) {
        int[] data = new int[]{1,41,14,5,8,5,6,7,11,9};
        int n=data.length;
        mergerSort (data,0,n-1);
        arrPrint(data);
    }

    public static void mergerSort(int[] data,int left,int right) {  //使用递归方法把数组分解成若干子数组
     if(left>=right){
         return;
     }
     else{
         int mid=(left+right)/2;
         mergerSort(data,left,mid);
         mergerSort(data,mid+1,right);
         merger(data,left,mid,right);
     }
    }
    public static void merger(int[] data,int left,int mid,int right){  //合并若干子数组
        int i=left;
        int j=mid+1;
        int k=0;
        int[] temp=new int[right-left+1];
//        两部分数组都还有数据
        while(i<=mid && j<=right){
//            小于等于保证有效性
            if(data[i]<=data[j]){
                temp[k++]=data[i++];
            }else{
                temp[k++]=data[j++];
            }
        }
//        判断两个数组中哪个还有元素
        int start=i;
        int end=mid;
        //胜下第二个数组
        if(j<=right){
            start=j;
            end=right;
        }
        //将剩余数组拷贝回temp数组
        while(start<=end){
            temp[k++]=data[start++];
        }
//        将temp中数组拷贝回data[left,right]数组
        for(i=0;i<=right-left;i++){
            data[left+i]=temp[i];
        }
    }
    public static void arrPrint(int[] data){
        for(int i=0;i<data.length;i++){
            System.out.print(data[i]+" ");
        }
    }
}

代码实现2:

package data.Sort;
public class MergerSort1 {
        public static int[] mergeSort(int[] nums, int left, int right) {
            if (left==right)
                return new int[] { nums[left] };

            int mid = left+ (right - left) / 2;
            int[] leftArr = mergeSort(nums, left, mid); //左有序数组
            int[] rightArr = mergeSort(nums, mid + 1, right); //右有序数组
            int[] newNum = new int[leftArr.length + rightArr.length]; //新有序数组

            int m = 0, i = 0, j = 0;
            while (i < leftArr.length && j < rightArr.length) {
                newNum[m++] = leftArr[i] < rightArr[j] ? leftArr[i++] : rightArr[j++];
            }
            while (i < leftArr.length)
                newNum[m++] = leftArr[i++];
            while (j < rightArr.length)
                newNum[m++] = rightArr[j++];
            return newNum;
        }

        public static void main(String[] args) {
            int[] nums = new int[] { 9, 8, 7, 6, 5, 4, 3, 2, 10 };
            int[] newNums = mergeSort(nums, 0, nums.length - 1);
            for (int x : newNums) {
                System.out.print(x+",");
            }
        }
    }


四,归并排序算法复杂度分析

  • 归并排序中,用到了一个临时数组,故空间复杂度为O(N)

  • 由归并排序的递归公式:T(N) = 2T(N/2) + O(N) 可知时间复杂度为O(NlogN),数组的初始顺序会影响到排序过程中的比较次数,但是总的而言,对复杂度没有影响。平均情况 or 最坏情况下 它的复杂度都是O(NlogN)

  • 归并排序是一个稳定的排序算法

  • 此外,归并排序中的比较次数是所有排序中最少的。原因是,它一开始是不断地划分,比较只发生在合并各个有序的子数组时。因此,JAVA的泛型排序类库中实现的就是归并排序。因为:对于JAVA而言,比较两个对象的操作代价是很大的(根据Comparable接口的compareTo方法进行比较),而移动两个对象,其实质移动的是引用,代价比较小。(排序本质上是两种操作:比较操作和移动操作)

    java.util.Arrays.sort(T[] arr)使用的是归并排序
    java.util.Arrays.sort(int[] arr) 使用的是快速排序

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值