排序算法(五):归并排序

版权声明:文章为作者原创,若要转载请获得作者同意。尊重版权,从你我做起! https://blog.csdn.net/qq_37768971/article/details/88777334

一、排序方法:

冒泡排序

二、基本原理

思考:归并排序本质是将N个元素进行2分,直至剩下1个元素,分割完成耗时O(logn)。然后思考如何进行归并,若每次处理只耗时n,则可以达到O(nlogn)的时间复杂度。
(1)分割,直至剩下一个元素就无须再排序

(2)归并,先复制一份数组。然后用蓝色标记当前数组,两个红色标记表示复制数组的左半边第一个元素和右半边第一个元素,逐个进行比较就能够达到N这个级别,本质上是用空间换时间,但是由于计算机的空间相对于时间要廉价很多,因此追求时间快更重要。

三、实现代码:

package IMUHERO;
import java.util.*;
public class MergeSort {

    public MergeSort(){};
    //此处定义的插入排序用来优化归并排序
    private static void insertionSort(Comparable[]arr,int left,int right){
        for (int i=left+1;i<=right;i++){
            Comparable temp=arr[i];
            int j=i;
            for (;j>left&&temp.compareTo(arr[j-1])<0;j--){
                    arr[j]=arr[j-1];
            }
            arr[j]=temp;
        }
    }
    //用户使用的静态函数,用来归并排序
    public static void  sort(Comparable[]arr){
        int len=arr.length;
        sort(arr,0,len-1);
    }
    //该函数用来向下分割,向上归并,分割到最后一个元素后向上排序和归并
    private static void sort(Comparable[]arr,int left,int right){
        if (right-left<=15){
            insertionSort(arr,left,right);
            return;
        }
        int mid =(left+right)/2;
        sort(arr,left,mid);
        sort(arr,mid+1,right);
        if (arr[mid].compareTo(arr[mid+1])>0) {
            merge(arr, left, mid, right);
        }
    }

//    merge方法用于实现归并的排序功能
//    基本的方法是先复制想要排序的两个数组为一个数组,同时定义左半边数组的第一个元素为i,右半边数组的第一个元素为j
//    然后定义原来两个数组最左边第一个元素为K,逐步增大K,比较复制的数组两者的大小,将比较中较小的元素逐渐添加进当前数组
//    完成排序
    private static void merge (Comparable[]arr,int left,int mid,int right){
        //下面的方法将arr中的元素复制到copy中;
        int len=right-left+1;
        Comparable [] copy=new Comparable[len];
        for (int c=left;c<=right;c++){
            copy[c-left]=arr[c];
        }
        //定义k为当前数组的第一个下标,i为复制数组左半边第一个下标,j为复制数组右半边第一个下标:
        //注意右半边第一个元素是mid+1-left;
        int k=left,i=0,j=mid+1-left;
        int copyMid=mid-left;
        int copyRight=right-left;
        //@实现排序:
        //如果左边的下标已经超过了mid,则之间将剩余右边元素拷贝进原数组剩余位置就行
        for (;k<=right;k++) {       //最外层循环判断当前排序是否完成
            if (i > copyMid) {
                arr[k]=copy[j];
                j++;
            }
            else if (j>copyRight){  //注意此处要用else if 不要用if,因为这四种情况是互相排斥的,发生了其中一种;另一种就不会发生
                arr[k]=copy[i];
                i++;
            }
            else if (copy[i].compareTo(copy[j])<0){
                arr[k]=copy[i];
                i++;
            }
            else {
                arr[k]=copy[j];
                j++;
            }
        }

    }


}


方法二(拓展):自顶向下的归并排序:

package IMUHERO;

import java.util.*;

public class MergeSortBU {

    // 我们的算法类不允许产生任何实例
    private MergeSortBU() {
    }

    // 将arr[l...mid]和arr[mid+1...r]两部分进行归并
    private static void merge(Comparable[] arr, int l, int mid, int r) {

        Comparable[] aux = Arrays.copyOfRange(arr, l, r + 1);

        // 初始化,i指向左半部分的起始索引位置l;j指向右半部分起始索引位置mid+1
        int i = l, j = mid + 1;
        for (int k = l; k <= r; k++) {

            if (i > mid) {  // 如果左半部分元素已经全部处理完毕
                arr[k] = aux[j - l];
                j++;
            } else if (j > r) {   // 如果右半部分元素已经全部处理完毕
                arr[k] = aux[i - l];
                i++;
            } else if (aux[i - l].compareTo(aux[j - l]) < 0) {  // 左半部分所指元素 < 右半部分所指元素
                arr[k] = aux[i - l];
                i++;
            } else {  // 左半部分所指元素 >= 右半部分所指元素
                arr[k] = aux[j - l];
                j++;
            }
        }
    }


    public static void sort(Comparable[] arr) {
        int n = arr.length;
        // Merge Sort Bottom Up 无优化版本
//        for (int sz = 1; sz < n; sz *= 2)
//            for (int i = 0; i < n - sz; i += sz+sz)
//                // 对 arr[i...i+sz-1] 和 arr[i+sz...i+2*sz-1] 进行归并
//                merge(arr, i, i+sz-1, Math.min(i+sz+sz-1,n-1));

        // Merge Sort Bottom Up 优化
        // 对于小数组, 使用插入排序优化
        for (int i = 0; i < n; i += 16)
            insertionSort(arr, i, Math.min(i + 15, n - 1));

        for (int sz = 16; sz < n; sz += sz)
            for (int i = 0; i < n - sz; i += sz + sz)
                // 对于arr[mid] <= arr[mid+1]的情况,不进行merge
                if (arr[i + sz - 1].compareTo(arr[i + sz]) > 0)
                    merge(arr, i, i + sz - 1, Math.min(i + sz + sz - 1, n - 1));
    }
    //此处的插入排序用来优化归并排序
    private static void insertionSort(Comparable[] arr, int left, int right) {
        for (int i = left + 1; i <= right; i++) {
            Comparable temp = arr[i];
            int j = i;
            for (; j > left && temp.compareTo(arr[j - 1]) < 0; j--) {
                arr[j] = arr[j - 1];
            }
            arr[j] = temp;
        }
    }
}


注:关于排序的所有代码都放在我的Github上,有需要的同学可以自行Fork,如果觉得还不错,可以打个☆Star哦~~~

猜你喜欢

转载自blog.csdn.net/qq_37768971/article/details/88777334