1. 程式人生 > >【Java常用排序演算法】歸併排序(二路歸併排序)

【Java常用排序演算法】歸併排序(二路歸併排序)

歸併排序的思路

歸併排序是通過“歸併”操作完成排序的,將兩個或者多個有序子表歸併成一個子表。歸併排序是“分治法”的一個非常典型的應用,同時它也是遞迴演算法的一個好的例項。它將問題分成一些小的問題然後遞迴求解,而治就是把分階段的答案拼起來。

二路歸併排序

  • 基本思想
    二路歸併排序就是將兩個有序子表歸併成一個有序表。首先我們得有一個演算法用於歸併:兩個有序表放在同一陣列的相鄰位置上,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--; } } }