歸併排序(MergeSort)遞歸與非遞歸的實現

主要關注一下非遞歸版本,其實就是模擬了從長度爲1的子段,不斷長度翻倍,一直到最後爲全長的過程。】

歸併的思想是: 
1.將原數組首先進行兩個元素爲一組的排序,然後合併爲四個一組,八個一組,直至合併整個數組; 
2.合併兩個子數組的時候,需要藉助一個臨時數組,用來存放當前的歸併後的兩個數組; 
3.將臨時數組複製回原數組對應的位置。

代碼中最後將tmp數組中的值寫回原數組中。(注意歸併爲穩定的排序方法!)

package mergesort;

import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;
//歸併排序的非遞歸算法
public class MergeSort{
    public static void main(String args[]){
        MergeSort mer = new MergeSort();
        int[] array = mer.getArray();
        System.out.println("OriginalArray:" + Arrays.toString(array));
        mer.mergeSort(array);
        System.out.println("SortedArray:" + Arrays.toString(array));
    }
    public int[] getArray(){
        Scanner cin = new Scanner(System.in);
        System.out.print("Input the length of Array:");
        int length = cin.nextInt();
        int[] arr = new int[length];
        Random r = new Random();
        for(int i = 0; i < length; i++){
            arr[i] = r.nextInt(100);
        }
        cin.close();
        return arr;
    }
//////////開始/////////////////////////

    public void mergeSort(int[] a){
        int len = 1;         //子段長度從1開始
        while(len < a.length){
            for(int i = 0; i < a.length; i += 2*len){  //每2*len段執行一次小歸併
                merge(a, i, len);
            }
            len *= 2;
        }
    }

    public void merge(int[] a, int i, int len){
        int start = i;         //左半段開始
        int len_i = i + len;   //前半部分的結束標記位,左半段長度len
        int j = i + len;       //右半段開始
        int len_j = j +len;    //後半部分的結束標記位,右半段長度len
        int[] temp = new int[2*len];   //tmp數組長度2*len
        int count = 0;
        while(i < len_i && j < len_j && j < a.length){  
            if(a[i] <= a[j]){
                temp[count++] = a[i++];
            }
            else{
                temp[count++] = a[j++];
            }
        }
        while(i < len_i && i < a.length){//將各段剩餘部分寫入。注意:這裏i也有可能超過數組長度
            temp[count++] = a[i++];
        }
        while(j < len_j && j < a.length){
            temp[count++] = a[j++];
        }
        count = 0;         //將tmp中排序結果寫回原數組中
        while(start < j && start < a.length){
            a[start++] = temp[count++];
        }
    }
}

遞歸算法的實現代碼如下:

public class MergeSort {
    public static void mergeSort(int[] data,int left,int right){ //left,right均爲數字元素下標
        if(left<right){
            int half=(left+right)/2;
            mergeSort(data,left,half);
            mergeSort(data,half+1,right);
            merge(data,left,right);
        }
    }
    public static void merge(int []a,int l,int h){
        int mid=(l+h)/2;
        int i=l;
        int j=mid+1;
        int count=0;
        int temp[]=new int[h-l+1];
        while(i<=mid&&j<=h){
            if(a[i]<a[j]){
                temp[count++]=a[i++];
            }else{
                temp[count++]=a[j++];
            }        
        }
        while(i<=mid){
            temp[count++]=a[i++];
        }
        while(j<=h){
            temp[count++]=a[j++];
        }
        count=0;
        while(l<=h){
            a[l++]=temp[count++];
        }
    }
   
}

歸併排序的時間複雜度爲O(n*log2n),空間複雜度爲O(n)

歸併排序是一種穩定的排序方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章