合并排序是建立在歸并操作上的一種有效的排序算法。該算法是采用分治法的一個非常典型的應用。
合并排序法是將兩個(或兩個以上)有序表合并成一個新的有序表,即把待排序序列分為若干個子序列,每個子序列是有序的。然后再把有序子序列合并為整體有序序列。
將已有序的子序列合并,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合并成一個有序表,稱為2-路歸并。合并排序也叫歸并排序。
算法基本思想:
- 首先將未排序的數組,進行拆分成n個單一的數據。
- 然后將這n個數據按照索引順序,兩兩組合、排序。(例如:有8個數據,那么第一個和第二個組合,第三個和第四個組合。。。如有未組合的數據這放任其暫時不管)
- 將上面已經兩兩組合、排序好的數據看成是一個“元素”,再進行兩兩組合、排序。。。
- 重復上述的步驟,最后就得到已經排序好的數組。
示意圖
代碼實現:
import java.util.Arrays;
import java.util.Date;
/**
* Created by noonbiteun
* Date: 2017/8/1
*/
public class MergeSort {
private static void merge(int[] unsortArr, int frontIndex, int backIndex, int lastIndex, int[] sortArr) {
int i = frontIndex;//前半段的起始索引
int j = backIndex;//后半段的起始索引
int k = 0;
//合并兩個小分組
while (i < backIndex && j < lastIndex) {
if (unsortArr[i] < unsortArr[j]) {
sortArr[k++] = unsortArr[i++];
} else {
sortArr[k++] = unsortArr[j++];
}
}
while (i < backIndex) {
//前半段還有數據
sortArr[k++] = unsortArr[i++];
}
while (j < lastIndex) {
//后半段還有數據
sortArr[k++] = unsortArr[j++];
}
for (int l = 0; l < k; l++) {
//將排序好的數放回
unsortArr[frontIndex + l] = sortArr[l];
}
}
public static void sort(int[] arr, int first, int last, int[] sorted) {
if (first < last - 1) {
int back = (first + last) / 2;
sort(arr, first, back, sorted);
sort(arr, back, last, sorted);
merge(arr, first, back, last, sorted);
}
}
public static void main(String[] args) {
int[] arr = new int[10];
//初始化數組
for (int i = 0; i < 10; i++) {
arr[i] = (int) (Math.random() * (100 + 1));
}
long t1 = new Date().getTime();
System.out.println("原始的順序: "+ Arrays.toString(arr));
MergeSort.sort(arr, 0, arr.length, new int[arr.length]);
long t2 = new Date().getTime();
System.out.println("排序后順序: "+ Arrays.toString(arr));
System.out.println("耗時:"+(t2-t1)+" ms");
}
}
輸出結果:
運行結果
分析小結:
歸并排序是穩定排序,它也是一種十分高效的排序,能利用完全二叉樹特性的排序一般性能都不會太差。java中Arrays.sort()采用了一種名為TimSort的排序算法,就是歸并排序的優化版本。從上文的圖中可看出,每次合并操作的平均時間復雜度為O(n),而完全二叉樹的深度為|log2n|??偟钠骄鶗r間復雜度為O(nlogn)。而且,歸并排序的最好,最壞,平均時間復雜度均為O(nlogn)。