【Java常用排序演算法】歸併排序(二路歸併排序)
阿新 • • 發佈:2018-12-23
歸併排序的思路
歸併排序是通過“歸併”操作完成排序的,將兩個或者多個有序子表歸併成一個子表。歸併排序是“分治法”的一個非常典型的應用,同時它也是遞迴演算法的一個好的例項。它將問題分成一些小的問題然後遞迴求解,而治就是把分階段的答案拼起來。
二路歸併排序
- 基本思想
二路歸併排序就是將兩個有序子表歸併成一個有序表。首先我們得有一個演算法用於歸併:兩個有序表放在同一陣列的相鄰位置上,arr[left]到arr[center-1]為第一個有序表,arr[center]到arr[right]是第二個有序表。每次從兩段中取出一個進行比較,小的先放入一個temp陣列,最後將比較剩下的直接放到temp中去,最後將temp又複製回arr。這是“治”。
下面說“分”,只需要遞迴地將前半部分和後半部分的資料各自歸併排序即可。 - 例子
{3,6,1,7,9,4,5,8,2}
二路歸併排序的過程如圖所示:
- 演算法分析
每一趟歸併的時間複雜度為O(n),共需要進行⌈log2n⌉趟。對應的演算法的時間複雜度為O(nlog2n)。歸併排序的空間複雜度O(n)。另外,歸併排序中歸併的演算法並不會將相同關鍵字的元素改變相對次序,所以歸併排序是穩定的。 - Java程式碼實現
package com.gray;
import java.util.Arrays;
public class MergeSort {
public static void main(String args[]) {
int a[] = {3, 6, 1, 7, 9, 4, 5, 8, 2};
mergeSort(a);
System.out.println("排序後:" + Arrays.toString(a));
}
private static void mergeSort(int[] arr) {
mergeSort(arr, new int[arr.length], 0, arr.length - 1);
}
private static void mergeSort(int[] arr, int[] temp, int left, int right) {
if (left < right) {
int center = (left + right) / 2;
mergeSort(arr, temp, left, center); // 左邊
mergeSort(arr, temp, center + 1, right); // 右邊
merge(arr, temp, left, center + 1, right); // 合併兩個有序
}
}
/**
* 將兩個有序表歸併成一個有序表
*
* @param arr
* @param temp 臨時陣列
* @param leftPos 左邊開始下標
* @param rightPos 右邊開始下標
* @param rightEnd 右邊結束下標
*/
private static void merge(int[] arr, int[] temp, int leftPos, int rightPos, int rightEnd) {
int leftEnd = rightPos - 1; // 左邊結束下標
int tempPos = leftPos; // 從左邊開始算
int numEle = rightEnd - leftPos + 1; // 元素個數
while (leftPos <= leftEnd && rightPos <= rightEnd) {
if (arr[leftPos] <= arr[rightPos])
temp[tempPos++] = arr[leftPos++];
else
temp[tempPos++] = arr[rightPos++];
}
while (leftPos <= leftEnd) { // 左邊如果有剩餘
temp[tempPos++] = arr[leftPos++];
}
while (rightPos <= rightEnd) { // 右邊如果有剩餘
temp[tempPos++] = arr[rightPos++];
}
// 將temp複製到arr
for (int i = 0; i < numEle; i++) {
arr[rightEnd] = temp[rightEnd];
rightEnd--;
}
}
}