資料結構之排序:歸併排序
阿新 • • 發佈:2019-02-13
歸併排序(Merging Sort)是與插入排序、交換排序、選擇排序不同的另一類排序方法。歸併的含義時將兩個(二路歸併)或兩個以上(多路歸併)的有序表合併成一個新的有序表。此處只討論二路歸併。
基本思想
將待排序序列r[0]到r[n-1]看成是一個含有n個長度為1的有序子表,將這些子表進行兩兩歸併,得到[n/2]個子表;然後再將這[n/2]個子表進行兩兩歸併,直到最後得到一個長度為n的有序表為止。
效能分析
空間複雜度:需要一個與待排序序列登場的輔助陣列來存放排序過程中的中間結果,所以空間複雜度為
時間複雜度:最好最壞和平均的時間複雜度均為
穩定性:是穩定的。
java實現程式碼:
/**
* 歸併排序: O(nlogn)
* 遞迴實現:合併兩個已經排序的表(一個數組儲存)
* @param iniArr 原始陣列(包含兩個已經排序的表)
* @param resArr 排序陣列
* @param left 最左索引
* @param right 最優索引
*/
public static <T extends Comparable<T>> void mergeSort(T[] iniArr,
T[] resArr, int left, int right) {
if(left < right) {
int center = (right + left) / 2;
mergeSort(iniArr, resArr, left, center);
mergeSort(iniArr, resArr, center + 1, right); // 注意center+1
merge(iniArr, resArr, left, center + 1, right);
}
}
/**
* 合併歸併排序的結果
* @param iniArr 原始陣列
* @param resArr 排序陣列
* @param leftPos 左邊起點索引
* @param rightPos 右邊起點索引
* @param rightEnd 右邊結束索引
*/
public static <T extends Comparable<T>> void merge(T[] iniArr, T[] resArr,
int leftPos, int rightPos, int rightEnd) {
int leftEnd = rightPos - 1; // 左序列結束索引
int nElements = rightEnd - leftPos + 1; // 序列中元素數目
int tmpPos = leftPos; // resArr陣列索引
// 左右序列比較排序
while(leftPos <= leftEnd && rightPos <= rightEnd) {
if (iniArr[leftPos].compareTo(iniArr[rightPos]) <= 0) {
resArr[tmpPos++] = iniArr[leftPos++];
} else {
resArr[tmpPos++] = iniArr[rightPos++];
}
}
// 最後一次比較後,拷貝所有剩餘的左邊元素
while(leftPos <= leftEnd) {
resArr[tmpPos++] = iniArr[leftPos++];
}
// 最後一次比較後,拷貝所有剩餘的右邊元素
while(rightPos <= rightEnd) {
resArr[tmpPos++] = iniArr[rightPos++];
}
// 將結果陣列替換原陣列,參與後續遞迴的歸併排序
// 最後的結果iniArr和resArr陣列都已經經過了排序,完全一致
for (int i = 0; i < nElements; i++) {
iniArr[rightEnd] = resArr[rightEnd];
rightEnd--;
}
}
參考:
1. 劉小晶,資料結構——Java語言描述(第2版),清華大學出版社
2. MARK A W, 資料結構與演算法分析: Java 語言描述,機械工業出版社