概念
過程
- 分解:將n 個元素分成個含n/2 個元素的子序列;
- 解決:對兩個子序列遞迴地排序
- 合併:合併兩個已排序的子序列以得到排序結果
和快排不同的是
- 歸併的分解較為隨意
- 重點是合併
- 需要額外開闢陣列空間
程式碼實現
public static void mergeSort(int[] arr){
if(arr == null||arr.length<2) return; //陣列元素至少為2
mergeSort(arr,0,arr.length-1);
}
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);
}
public static void merge(int[] arr, int L, int m, int R){
int[] help = new int[R-L+1]; //輔助陣列
int i = 0; //輔助陣列下標
int p1 = L; //第一個待合併陣列起點
int p2 = m + 1; //第二個待合併陣列起點
while(p1 <= m && p2 <= R){ //排好的部分拷貝到輔助陣列
help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
}
while(p1 <= m){ //繼續處理剩下的陣列
help[i++] = arr[p1++];
}
while(p2 <= R){ //繼續處理剩下的陣列
help[i++] = arr[p2++];
}
for (int j = 0; j < help.length; j++) { //拷貝回原陣列
arr[L + j]=help[j];
}
}
複雜度分析
套用master公式T(N) = a*T(N/b) + O(N^d)
a=2,b=2,d=1
log(b,a) = d -> 時間複雜度為O(N^d * logN) =O(NlogN)
額外空間複雜度 O(N)
所以:
- 時間複雜度:O(NlogN)
- 空間複雜度:O(N)
- 穩定性:穩定
- 非原址排序
經典例題
劍指 Offer 51. 陣列中的逆序對
在陣列中的兩個數字,如果前面一個數字大於後面的數字,則這兩個數字組成一個逆序對。輸入一個陣列,求出這個陣列中的逆序對的總數。
示例 1:
輸入: [7,5,6,4]
輸出: 5
限制:
0 <= 陣列長度 <= 50000
稍微修改一下歸併排序程式碼即可
class Solution {
private int ans = 0; //宣告例項變數
public int reversePairs(int[] nums) {
mergeSort(nums, 0, nums.length - 1);
return ans;
}
public void mergeSort(int[] arr, int low, int high) {
if (arr.length < 2 || low >= high) return;
int mid = low + ((high - low) >> 1);
mergeSort(arr, low, mid);
mergeSort(arr, mid + 1, high);
merge(arr, low, mid, high);
}
public void merge(int[] arr, int low, int mid, int high) {
int[] helper = new int[high - low + 1];
int i = low;
int j = mid + 1;
int k = 0;
while (i <= mid && j <= high) {
if (arr[i] <= arr[j]) {
helper[k++] = arr[i++];
} else {
ans += mid - i + 1; //注意:如果arr[i]>arr[j]則i~mid這個區間的所有數都大於arr[j],因為[low……mid]和[mid+1……high]是已經排好序的。
helper[k++] = arr[j++];
}
}
while (i <= mid) {
helper[k++] = arr[i++];
}
while (j <= high) {
helper[k++] = arr[j++];
}
for (int m = 0; m < helper.length; m++) {
arr[low + m] = helper[m];
}
}
}