基於分治策略的排序算法:合併排序和快速排序

參考教材:算法設計與分析(第3版) 王曉東 編著 清華大學出版社
首先介紹什麼是分治法?
分治法的基本思想是將一個規模爲n的問題分解成k個規模較小的子問題,這些子問題互相獨立且與原問題相同。遞歸地解決這些子問題,然後將各子問題的解合併得到原問題的解。

合併排序

合併排序算法是用分治策略實現對n個元素進行排序的算法。其基本思想是:將待排序元素分成大小大致相同的2個子集合,分別對2個子集合進行排序,最終將排好序的子集合合併成爲所要求的排好序的集合。
代碼:

public class MergeSort {
    /**
     * @param int[] 未排序數組
     * @return int[] 排完序數組
     */
    private int[] sort(int[] nums, int low, int high) {
        int mid = (low + high) / 2;
        if (low < high) {
            // 左邊
            sort(nums, low, mid);
            // 右邊
            sort(nums, mid + 1, high);
            // 左右歸併
            merge(nums, low, mid, high);
        }
        return nums;
    }

    private void merge(int[] nums, int low, int mid, int high) {
        int[] temp = new int[high - low + 1];
        int i = low;// 左指針
        int j = mid + 1;// 右指針
        int k = 0;
        // 把較小的數先移到新數組中
        while (i <= mid && j <= high) {
            if (nums[i] < nums[j]) {
                temp[k++] = nums[i++];
            } else {
                temp[k++] = nums[j++];
            }
        }
        // 把左邊剩餘的數移入數組
        while (i <= mid) {
            temp[k++] = nums[i++];
        }
        // 把右邊邊剩餘的數移入數組
        while (j <= high) {
            temp[k++] = nums[j++];
        }
        // 把新數組中的數覆蓋nums數組
        for (int k2 = 0; k2 < temp.length; k2++) {
            nums[k2 + low] = temp[k2];
        }
    }

    public int[] sortMerge(int[] array) {
        return sort(array, 0, array.length - 1);
    }

    public static void main(String[] args) {
        int[] a = { 4, 5, 1, 5, 3, 8, 1, 6, 9, 7, 2, 3, 5, 0, -5, -6, -7, -4 };
        new MergeSort().sortMerge(a);
        for (int i : a) {
            System.out.print(i + " ");
        }
    }
}

測試數據運行結果:

-7 -6 -5 -4 0 1 1 2 3 3 4 5 5 5 6 7 8 9 

快速排序

快速排序算法是基於分治策略的另一個排序算法。其基本思想是,對於輸入的子數組a[ p : r ],按以下三個步驟進行排序。

  1. 分解(divide):以a[ p ]爲基準元素將a[ p : r ]劃分成3段a[ p : q - 1 ],a[ q ]和a[ q + 1 : r ],使得a[ p : q - 1 ]中任何元素都小於等於a[ q ],a[ q + 1 : r ]中任何元素都大於等於a[ q ]。下標q在劃分過程中確定。
  2. 遞歸求解(conquer):通過遞歸調用快速排序算法,分別對a[ p : q - 1 ]和a[ q + 1 : r ]進行排序。
  3. 合併(merge)。

代碼:

public class QuickSort {
    /**
     * @param int[] 未排序數組
     * @return int[] 排完序數組
     */
    public int[] sortQuick(int[] array) {
        return quickSort(array, 0, array.length - 1);
    }

    private int[] quickSort(int[] arr, int low, int heigh) {
        if (low < heigh) {
            int division = partition2(arr, low, heigh);
            quickSort(arr, low, division - 1);// 對左半段排序
            quickSort(arr, division + 1, heigh);// 對右半段排序
        }
        return arr;
    }

    // 分水嶺,基位,左邊的都比這個位置小,右邊的都大
    private int partition(int[] arr, int low, int heigh) {
        int base = arr[low]; // 用子表的第一個記錄做樞軸(分水嶺)記錄
        while (low < heigh) { // 從表的兩端交替向中間掃描
            while (low < heigh && arr[heigh] >= base) {
                heigh--;
            }
            // base 賦值給 當前 heigh 位,base 挪到(互換)到了這裏,heigh位右邊的都比base大
            swap(arr, heigh, low);
            while (low < heigh && arr[low] <= base) {
                low++;
            }
            // 遇到左邊比base值大的了,換位置
            swap(arr, heigh, low);
        }
        // now low = heigh;
        return low;
    }

    // 第二種partition,本質一樣,代碼略有不同
    private int partition2(int[] arr, int low, int heigh) {
        int i = low, j = heigh + 1;
        int base = arr[low];
        // 將<base的元素交換到左邊區域
        // 將>base的元素交換到右邊區域
        while (true) {
            // 從左往右找,找到第一個比base大的,記錄位置i,即arr[i]>base
            while (arr[++i] < base && i < heigh)
                ;
            // 從右往左找,找到第一個比base小的,記錄位置j,即arr[j]<base
            while (arr[--j] > base)
                ;
            // 判斷是否有交換的必要
            if (i >= j)
                break;
            swap(arr, i, j);
        }
        // 將base放入正確位置,即arr[low]與arr[j]互換位置
        arr[low] = arr[j];
        arr[j] = base;
        // 現在j左邊的全部小於j右邊的,返回下標j
        return j;
    }

    private void swap(int[] arr, int a, int b) {
        int temp;
        temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }

    public static void main(String[] args) {
        int[] a = { 4, 5, 1, 5, 3, 8, 1, 6, 9, 7, 2, 3, 5, 0, -5, -6, -7, -4 };
        new QuickSort().sortQuick(a);
        for (int i : a) {
            System.out.print(i + " ");
        }
    }
}

我的收藏品:java常用的7大排序算法彙總

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章