歸併排序的Java實現、效能分析以及適用場景
阿新 • • 發佈:2019-02-12
1.歸併排序的Java實現:
程式碼如下:
package com.zm.testSort;
/**
* 歸併排序
* @author zm
*/
public class MergeSort {
public static void getMergeSort(int[] a) {
if(a == null || a.length < 2) {
return;
}
getMergeSort(a, 0, a.length-1);
}
public static void getMergeSort (int[] a, int low, int high) {
if(high > low) {
int mid = (high + low)/2;//獲取中間值
getMergeSort(a, low, mid);//分治
getMergeSort(a, mid+1, high);//分治
merge(a, low, mid, high);//合併兩個子序列
}
}
/**
* 思想:將輔助陣列分為兩部分,如[a, b] [c, d],每個子序列是有序的,即a<b,c<d,因此,每回都是將
* 第二部分的最小值c與第一部分的最小值a比較,如果c<a,則說明c是最小的,將c賦給原陣列的第一個位置且用d與a比較,如果
* c>a,則說明a是最小的,將a賦給原陣列的第一個位置且再比較b與c。
*/
public static void merge(int[] a, int low, int mid, int high) {//合併兩個子序列
int[] aux = new int[a.length];//建立輔助陣列
for(int k = low; k <= high; k++) {//將a陣列賦值給輔助陣列
aux[k] = a[k];
}
int i = low;//用於操作輔助陣列
int j = mid + 1;//用於操作輔助陣列
int k = low;//用於儲存正確排序的a陣列的值
for(;i <= mid && j <= high;k++) {
if(aux[j] >= aux[i]) {//輔助陣列的第二部分的第一個值開始,與第一部分的第一個值比較
a[k] = aux[i++];//如果大於,將索引i的元素賦給a陣列的索引k位置,同時索引i往後移
}else {
a[k] = aux[j++];//如果小於,將索引j的元素賦給a陣列的索引k位置,同時索引j往後移
}
}
while(i <= mid) {//如果此時i還在[0, mid]範圍之內,說明剩下的i~mid之間的元素是最大的,將這些元素全部插入到a陣列的最後
a[k++] = aux[i++];
}
while(j <= high) {//如果此時j還在[mid+1, high]範圍之內,說明剩下的j~high之間的元素是最大的,將這些元素全部插入到a陣列的最後
a[k++] = aux[j++];
}
}
public static void main(String[] args) {
int[] a = {3, 5, 1, 2, 6, 4, 7, 11, 23, 44, 3, 34, 8, 23, 6, 9};
getMergeSort(a);
System.out.print("歸併排序:");
for(int i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
}
}
2.歸併排序的效能分析:
時間複雜度:
1. 最好情況:O(nlog2(n))
2. 平均情況:O(nlog2(n))
3. 最壞情況:O(nlog2(n))
空間複雜度:O(n)
穩定性:穩定(相同元素的相對位置不會改變)
3.適用場景
3.1:)若n較大,則應採用時間複雜度為O(nlog2(n))的排序方法:快速排序、堆排序或歸併排序。
快速排序是目前基於比較的內部排序中被認為是最好的方法,當待排序的關鍵字是隨機分佈時,快速排序的平均時間最短;
堆排序所需的輔助空間少於快速排序,並且不會出現快速排序可能出現的最壞情況。這兩種排序都是不穩定的。
若要求排序穩定,則可選用歸併排序。但前面介紹的從單個記錄起進行兩兩歸併的排序演算法並不值得提倡,通常可以將它和直接插入排序結合在一起使用。先利用直接插入排序求得較長的有序子序列,然後再兩兩歸併之。因為直接插入排序是穩定的,所以改進後的歸併排序仍是穩定的。
3.2:歸併排序和快速排序一樣,都採用了分治的思想。