歸併排序和基數排序

hancc_824發表於2020-12-17
  1. 歸併排序

思想:歸併排序與上述基於交換,選擇排序的思想不一樣。“歸併”的含義是將兩個或兩個以上的有序列表組合成一個新的有序表。嘉定待排序表含有n個記錄,則可以看成是n個有序的字表,每個字表長度為1,然後兩兩歸併,得到n/2個長度為2或1的有序表;再兩兩歸併,…,如此重複,直到合併成一個長度為n的有序表位置,這種排序方法成為2-路歸併排序,如下為歸併排序示例。

在這裡插入圖片描述
Merge()的功能是將前後相鄰的兩個有序表歸併成為一個有序表的演算法。設兩段有序表A[low…mid],A[mid…high]存放在同一順序表中小林的位置上,先將它們複製到輔助陣列B中。每次從對B中的兩個端取出一個記錄進行關鍵字的比較,江較小者放入A中,將陣列B中有一段的下表超出其對應的表長時(即該段的所有元素已經完全複製到A中),將另一段中的剩餘部分直接複製到A中。

  • java程式碼實現:
/**
 * @author:cch
 * @description: 歸併排序
 * @date 2020/12/17
 */
public class MergeSort {

	public static void main(String[] args) {
		int arr[] = { 8, 4, 5, 7, 1, 3, 6, 2 };
		mergeSort(arr, 0, arr.length - 1);
		System.out.println(Arrays.toString(arr));
	}

	public static void mergeSort(int[] arr, int l, int r) {
		if (l == r) {
			return;
		}
		int mid = l + ((r - l) >> 1);
		mergeSort(arr, l, mid);
		mergeSort(arr, mid + 1, r);
		merge(arr, l, mid, r);

	}

	private static void merge(int[] arr, int l, int mid, int r) {
		int[] help = new int[r + 1 - l];
		int i = 0;
		int p1 = l;
		int p2 = mid + 1;

		// 兩邊做比較
		while (p1 <= mid && p2 <= r) {
			help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
		}
		// 左邊全部完了
		while (p2 <= r) {
			help[i++] = arr[p2++];
		}
		// 右邊全部完了
		while (p1 <= mid) {
			help[i++] = arr[p1++];
		}

		for (i = 0; i < help.length; i++) {
			arr[l + i] = help[i];
		}
	}

}
  • 效能分析:
    空間效率:Merge()操作中,輔助空間剛好要佔用n個單元,所以歸併排序的空間複雜度為O(n)。
    時間效率:每一趟歸併的時間複雜度為O(n),共需進行log2n趟歸併,所以演算法的時間複雜度為O(nlog2n)。
  • 穩定性:由於Merge()操作不會改變相同關鍵字記錄的相對次序,所以2-路歸併排序演算法是一個穩定得的排序演算法。
  1. 基數排序

思想:基數排序
是一種很特備的排序方法,他不是基於比較進行排序的,而是採用多關鍵字排序思想(即基於關鍵字各位的帶下進行排序的),藉助“分配”和“收集”兩種操作對單邏輯關鍵字進行排序。技術排序又可以分為最高位優先(MSD)排序和最低位優先(LSD)排序,如下為歸併排序示例。

在這裡插入圖片描述

  • java程式碼實現:
/**
 * @author:cch
 * @description: 基數排序
 * @date 2020/12/17
 */
public class RadixSort {
    public static void main(String[] args) {
        int[] arr = {63, 157, 189, 51, 101, 47, 141, 121, 157, 156,
                194, 117, 98, 139, 67, 133, 181, 12, 28, 0, 109};

        radixSort(arr);

        System.out.println(Arrays.toString(arr));
    }

    /**
     * 高位優先法
     *
     * @param arr 待排序列,必須為自然數
     */
    private static void radixSort(int[] arr) {
        //待排序列最大值
        int max = arr[0];
        int exp;//指數

        //計算最大值
        for (int anArr : arr) {
            if (anArr > max) {
                max = anArr;
            }
        }

        //從個位開始,對陣列進行排序
        for (exp = 1; max / exp > 0; exp *= 10) {
            //儲存待排元素的臨時陣列
            int[] temp = new int[arr.length];
            //分桶個數
            int[] buckets = new int[10];

            //將資料出現的次數儲存在buckets中
            for (int value : arr) {
                //(value / exp) % 10 :value的最底位(個位)
                buckets[(value / exp) % 10]++;
            }

            //更改buckets[i]for (int i = 1; i < 10; i++) {
                buckets[i] += buckets[i - 1];
            }

            //將資料儲存到臨時陣列temp中
            for (int i = arr.length - 1; i >= 0; i--) {
                temp[buckets[(arr[i] / exp) % 10] - 1] = arr[i];
                buckets[(arr[i] / exp) % 10]--;
            }

            //將有序元素temp賦給arr
            System.arraycopy(temp, 0, arr, 0, arr.length);
        }
    }
}

相關文章