12.快速排序

快排的思想:如果要排序數組中下標從 p 到 r 之間的一組數據,我們選擇 p 到 r 之間的任意一個數據作爲 pivot(分區點)。

  我們遍歷 p 到 r 之間的數據,將小於 pivot 的放到左邊,將大於 pivot 的放到右邊,將 pivot放到中間。經過這一步驟之後,數組 p 到 r 之間的數據就被分成了三個部分,前面 p 到 q-1之間都是小於 pivot 的,中間是 pivot,後面的 q+1 到 r 之間是大於 pivot 的。

  根據分治、遞歸的處理思想,我們可以用遞歸排序下標從 p 到 q-1 之間的數據和下標從 q+1 到r 之間的數據,直到區間縮小爲 1,就說明所有的數據都有序了。
在這裏插入圖片描述
如果我們用遞推公式來將上面的過程寫出來的話,就是這樣:

遞推公式:
quick_sort(p…r) = quick_sort(p…q-1) + quick_sort(q+1, r)
終止條件:
p >= r

  • 快速排序也可以很快解決top k問題
  • 和歸併排序相比解決了空間複雜度的問題,原地排序
  • 是不穩定排序,原因是因爲分區的過程涉及交換操作,i所在的位置第一個不符合標準的元素,後面接着還有不符合標準的元素,當我們再往後發現了j是符合標準的元素,此時就要交換i和j位置。此時原先在前的元素就跑到後面了。所以說是不穩定排序算法。
  • 時間複雜度是O(nlogn),極端情況下可能退化成O(n)。
public class SortQuick {

    public static void main(String[] args) {
        int a[] = {9, 8, 5, 6, 3, 4, 1, 2};
        new SortQuick().quicksort(a, 0, a.length - 1);
        for (int i = 0; i < a.length; i++) {
            System.out.print(a[i] + ", ");
        }
        System.out.println();
        new SortQuick().selectTopK(a, 3);
        for (int i = 0; i < 3; i++) {
            System.out.print(a[i] + ", ");
        }
    }

    public void selectTopK(int[] nums, int k) {
        int partition = partition(nums, 0, nums.length - 1);
        while (partition != k) {
            if (partition > k) {
                //說明還需要進一步縮小空間獲取前k大
                partition = partition(nums, 0, partition - 1);
            } else {
                //說明還需要擴大空間獲取前k大
                partition = partition(nums, partition + 1, nums.length - 1);
            }
        }
    }

    /**
     * 這裏是遞歸,遞歸都要使用遞歸公式來思考代碼的編寫
     *
     * @param nums
     * @param start
     * @param end
     */
    public void quicksort(int[] nums, int start, int end) {
        if (start >= end) {
            return;
        }
        int partition = partition(nums, start, end);
        quicksort(nums, start, partition - 1);
        quicksort(nums, partition + 1, end);
    }

    public int partition(int[] nums, int start, int end) {
        //選取最後一個作爲基點,比他小的放前面,比他大的放後面
        int point = end;
        int index = start;//從start到index的值比較小的
        for (int i = start; i <= end; i++) {
            if (nums[i] < nums[point]) {
                //如果當前i是滿足條件的,就把它放到index上
                int temp = nums[index];
                nums[index] = nums[i];
                nums[i] = temp;
                index++;
            }
        }
        //把基準數挪到角標這裏
        int temp = nums[index];
        nums[index] = nums[point];
        nums[point] = temp;
        return index;
    }
}


在這裏插入圖片描述

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