java排序(5):歸併排序和基數排序

一.歸併排序

1.基本思想

  歸併(Merge)排序法是將兩個(或兩個以上)有序表合併成一個新的有序表,即把待排序序列分爲若干個子序列,每個子序列是有序的。然後再把有序子序列合併爲整體有序序列。
  歸併排序就是利用歸併的思想實現的排序方法,效率比較高。其基本原理如下:對於給定的一組記錄,利用遞歸與分治技術將數據序列劃分成爲越來越小的半子表,在對半子表排序,最後再用遞歸方法將排好序的半子表合併成爲越來越大的有序序列。
  

2.思路

(1)申請空間,使其大小爲兩個已經排序序列之和,該空間用來存放合併後的序列
(2)設定兩個指針,最初位置分別爲兩個已經排序序列的起始位置
(3)比較兩個指針所指向的元素,選擇相對小的元素放入到合併空間,並移動指針到下一位置
(4)重複步驟3直到某一指針達到序列尾
(5)將另一序列剩下的所有元素直接複製到合併序列尾

這裏寫圖片描述

3.代碼

public class MergeSort {

    //兩個數組合並
    public static void merge(int[] nums, int low, int mid, int high) {
        int[] newArr = new int [high-low+1]; //新合併元素數組
        int i = low;   // 左指針
        int j = mid+1; // 右指針
        int k = 0;
        while(i<=mid && j<=high){   // 把較小的數先移到新數組中
            if(nums[i]<nums[j]){
                newArr[k++] = nums[i++];
            }else{
                newArr[k++] = nums[j++];
            }
        }

        while (i <= mid){   // 把左邊剩餘的數移入新數組中
            newArr[k++] = nums[i++];  
        }
        while (j <= high) {   // 把右邊邊剩餘的數移入新數組中
            newArr[k++] = nums[j++];
        }

         // 把新數組中的數覆蓋nums數組
        for (int temp = 0; temp < newArr.length; temp++) {
            nums[temp + low] = newArr[temp];
        }

    }

    public static void mergeSort(int[] nums, int low, int high) {
        int mid = low + (high-low)/2;  // 防止數字超出,堆棧溢出
        if(low<high){
            mergeSort(nums, low, mid);  // 左邊子數組
            mergeSort(nums, mid+1, high); //右邊子數組
            merge(nums, low, mid, high); //左右子數組合並
        }
    }
}

測試:

@Test
public void testMergeSort(){        
    int numbers[] = { 51, 46, 20, 18, 65, 97, 82, 30, 77, 50 };
    MergeSort.mergeSort(numbers, 0, numbers.length - 1);
    for(int i=0;i<numbers.length;i++){  
        System.out.print(numbers[i]+" ");  
    }  
}

結果:

18 20 30 46 50 51 65 77 82 97 

4.優缺點

歸併排序需要O(nlogn)的比較和O(nlogn)的數據移動。

(1)優點

①歸併排序的效率達到了巔峯
時間複雜度爲O(nlogn),這是基於比較的排序算法所能達到的最高境界。
②歸併排序是一種穩定的算法
這一點在某些場景下至關重要。
③歸併排序是最常用的外部排序方法
當待排序的記錄放在外存上,內存裝不下全部數據時,歸併排序仍然適用,當然歸併排序同樣適用於內部排序。

(2)缺點

歸併排序需要O(n)的輔助空間,而與之效率相同的快排和堆排分別需要O(logn)和O(1)的輔助空間,在同類算法中歸併排序的空間複雜度略高

二.基數排序

1.基本思想

基數排序(radix sort)屬於“分配式排序”(distribution sort),又稱“桶子法”(bucket sort)或bin sort,顧名思義,它是透過鍵值的部份資訊,將要排序的元素分配至某些“桶”中,藉以達到排序的作用,基數排序法是屬於穩定性的排序,其時間複雜度爲O (nlog(r)m),其中r爲所採取的基數,而m爲堆數,在某些時候,基數排序法的效率高於其它的穩定性排序法

2.思路

(1)假設數組中最大位數爲d,將數組按照最小位數排序。
(2)按照位數爲10^(d-1)位(個位,十位,百位)排序d次,數組即爲有序序列了
案例:
存在數組:{73, 22, 93, 43, 55, 14, 28, 65, 39, 81, 33, 100}
最大位數:3位
第1次按照個位排序:{100, 81, 22, 73, 93, 43, 33, 14, 55, 65, 28, 39 }
第2次按照十位排序:{100, 14, 22, 28, 33, 39, 43, 55, 65, 73, 81, 93 }
第3次按照百位排序:{ 14, 22, 28, 33, 39, 43, 55, 65, 73, 81, 93, 100}

3.代碼

public class RadixSort{
    public static void radixSort(int[] numbers, int d){  //d表示最大的數有多少位
        int n = 1; //取個位/十位/百位
        int[][]temp = new int[10][numbers.length]; //數組的第一維表示可能的餘數0-9
        int[]order = new int[10]; //數組order[i]用來表示該位是i的數的個數
        //i控制鍵值排序依據在哪一位
        for(int i=0; i<d; i++){
            int m = 0;

            for (int j = 0; j < numbers.length; j++) {
                int remainder = (numbers[j]/n)%10; //除10取餘
                temp[remainder][order[remainder]] = numbers[j];
                order[remainder]++;
            }

            for(int k=0; k<10; k++){
                if(order[k] != 0){
                    for (int l = 0; l < order[k]; l++) {
                        numbers[m] = temp[k][l];
                        m++;
                    }
                }
                order[k] = 0;
            }

            n *= 10;        
        }
    }
}

測試:

@Test
public void testRadixSort(){
    int[]data = {73, 22, 93, 43, 55, 14, 28, 65, 39, 81, 33, 100};
       RadixSort.radixSort(data, 3);
       for(int i = 0; i < data.length; i++){
           System.out.print(data[i] + " ");
       }
}

結果:

14 22 28 33 39 43 55 65 73 81 93 100 

4.優缺點

(1)優點

基數排序法是屬於穩定性的排序,其時間複雜度爲O (nlog(r)m),其中r爲所採取的基數,而m爲堆數,在某些時候,基數排序法的效率高於其它的穩定性排序法。

(2)缺點

不呈現時空局部性,因爲在按位對每個數進行排序的過程中,一個數的位置可能發生巨大的變化,所以不能充分利用現代機器緩存提供的優勢。同時計數排序作爲中間穩定排序的話,不具有原地排序的特點,當內存容量比較寶貴的時候,還是有待商榷

三.參考

http://blog.csdn.net/jianyuerensheng/article/details/51262984
http://blog.csdn.net/Touch_2011/article/details/6785881

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