排序算法之归并排序

Posted itblock

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序算法之归并排序相关的知识,希望对你有一定的参考价值。

一、原理

? 归并算法是采用分治法(Devide and Conquer)的一个典型应用,即先保证每个子序列有序,再将子序列进行合并,处理使得合并后的子序列有序,如此逐步得到一个有序的序列。

? 归并算法在实现上分为自下向上的迭代归并排序和自上向下的递归式的归并排序。下面将分别以代码形式实现两种实现方法。

二、代码实现

2.1 迭代实现方式的 java代码实现

package com.java;

public class MergeSortIterate 
    public static void main(String[] args)
        int[] arrs = 15,7,30,28,6,66,43,3,70,5;
        System.out.println("归并排序前:");
        display(arrs);
        mergeSort(arrs);
        System.out.println("归并排序后:");
        display(arrs);
    

    public static void mergeSort(int[] arrs) 
        int[] temp = new int[arrs.length];//临时空间,用于存放归并结果
        int squa = 1;//子序列起始长度为1
        while(squa < arrs.length)
            mergeDownToUp(arrs,temp,squa,arrs.length);
            squa = 2 * squa;
        
    

    public static void mergeDownToUp(int[] arrs, int[] temp, int squa, int length) 
        int left = 0,middle,right;

        while (left < length -2*squa + 1)//即right<length  length-right = length-2*squa+1 > left
            right = left + 2*squa -1;//即right的值是left的值加上两个相邻子组的长度减一
            middle = (left + right)/2;
            merge(arrs,temp,left,middle,right);
            left = left + 2*squa;
        

        //处理剩下的尾数
        if(left < length - squa + 1) //即middle<length 推导(length -middle = length - squa + 1 > left)
            merge(arrs,temp,left,left+squa-1,length-1);
        else
            while(left < length)
                if(temp[left] != arrs[left])
                    temp[left] = arrs[left];
                
                left = left + 1;
            
        
    

    public static void merge(int[] arrs, int[] temp, int start, int middle, int end) 
        int i = start,t = start,j = middle + 1;
        while (i <= middle && j<=end)
            if(arrs[i] <= arrs[j])
                temp[t] = arrs[i];
                t = t + 1;
                i = i + 1;
            else
                temp[t] = arrs[j];
                t = t + 1;
                j = j + 1;
            
        

        while (i <= middle)//将前半部分剩余的复制到temp
            temp[t] = arrs[i];
            t = t + 1;
            i = i + 1;
        

        while (j <= end)//将后半部分剩余的复制到temp
            temp[t] = arrs[j];
            t = t + 1;
            j = j + 1;
        
        while (start <= end)//将temp的数据覆盖arrs的数据
            if (arrs[start] != temp[start])
                arrs[start] = temp[start];
            
            start = start + 1;
        
    

    public static void display(int[] arrs)
        for(int i = 0;i < arrs.length;i++)
            System.out.print(" " + arrs[i] + " ");
        
        System.out.println();
    

运行结果如下:

归并排序前:
 15  7  30  28  6  66  43  3  70  5 
归并排序后:
 3  5  6  7  15  28  30  43  66  70 

2.2 递归实现方式的 java代码实现

package com.java;

public class RecursiveSort 

    public static void main(String[] args)
        int[] arrs = 15,7,30,28,6,66,43,3,70,5;
        System.out.println("归并排序前:");
        display(arrs);
        mergeSort(arrs);
        System.out.println("归并排序后:");
        display(arrs);
    


    public static void mergeSort(int[] arrs) 
        int []temp = new int[arrs.length];//临时空间,用于存放归并结果
        mergeUpToDown(arrs,0,arrs.length-1,temp);
    

    private static void mergeUpToDown(int[] arr,int left,int right,int []temp)
        if(left<right)
            int mid = (left+right)/2;
            mergeUpToDown(arr,left,mid,temp);//对左边进行归并排序,使得左子序列有序
            mergeUpToDown(arr,mid+1,right,temp);//对右边进行归并排序,使得右子序列有序
            merge(arr,temp,left,mid,right);//将两边的有序子数组进行合并
        
    

    public static void merge(int[] arrs, int[] temp, int start, int middle, int end) 
        int i = start,t = start,j = middle + 1;
        while (i <= middle && j<=end)
            if(arrs[i] <= arrs[j])
                temp[t] = arrs[i];
                t = t + 1;
                i = i + 1;
            else
                temp[t] = arrs[j];
                t = t + 1;
                j = j + 1;
            
        

        while (i <= middle)//将前半部分剩余的复制到temp
            temp[t] = arrs[i];
            t = t + 1;
            i = i + 1;
        

        while (j <= end)//将后半部分剩余的复制到temp
            temp[t] = arrs[j];
            t = t + 1;
            j = j + 1;
        
        while (start <= end)//将temp的数据覆盖arrs的数据
            if (arrs[start] != temp[start])
                arrs[start] = temp[start];
            
            start = start + 1;
        
    

    public static void display(int[] arrs)
        for(int i = 0;i < arrs.length;i++)
            System.out.print(" " + arrs[i] + " ");
        
        System.out.println();
    

运行结果如下:

归并排序前:
 15  7  30  28  6  66  43  3  70  5 
归并排序后:
 3  5  6  7  15  28  30  43  66  70 

三、复杂度分析

3.1 时间复杂度分析

? 归并排序类似于遍历二叉树,其需要遍历的次数即是二叉树的深度。由此可知归并排序的时间复杂度是O(n*log2n)。

3.2 空间复杂度分析

? 空间复杂度:空间复杂度是运行完一个程序所需要的内存的大小。即包括了存储算法本身所需要的空间,输入与输出数据所占空间,以及一些临时变量所占用的空间。一般而言,只比较额外空间,来比较算法的空间优越性。

? 由上述代码可知,归并排序需要一个长度和待排序数组一样长度的数组来存放临时数据,因此其空间复杂度是O(n)。

四、稳定性

归并排序中相等的元素不会改变位置,因此归并算法是稳定的算法。

以上是关于排序算法之归并排序的主要内容,如果未能解决你的问题,请参考以下文章

算法之-归并排序算法,插入排序算法

排序算法之归并排序(Java)

排序算法之归并排序(Java)

看动画学算法之:排序-归并排序

排序算法之归并排序

排序算法之归并排序