排序算法:快速排序

Sorting Algorithms:Quick Sort

前言

該博客用於本弱雞複習鞏固,打牢基礎,還望各大佬不吝賜教。html

基本思路

1.對一個未排序序列,假設從該序列中的元素中取一個基準值pivotkey,將小於pivotkey放左邊,大於pivotkey放右邊;
2.接着以該k爲中間,左右兩邊的分割做爲新的序列,從新進行1操做。
快排由於用到了遞歸操做,因此在簡單排序中性能不如直接插入排序,
而在大量數據排序時,遞歸產生的性能影響對於算法的總體性能優點能夠忽略。java

動圖示例

Quick Sort
Quick Sort

算法複雜度分析

平均 最壞 最好 穩定性 空間複雜度
O(nlogn) O(n^2) O(nlogn) 不穩定 O(logn)

p.s. 算法

  • 最壞狀況:待排序爲正序或逆序,這樣每次分割後的子序列一個之比上一次序列少一個元素,一個爲空。如 1 2 3 4 5 pivotkey=1;分割後一個序列爲 2 3 4 5 一個爲空,最終O(n^2)
  • 最好狀況:每一次分割都能平分,很均勻 O(nlogn)
  • 平均狀況:O(n*logn) 數學概括法
  • 空間複雜度:主要由遞歸而產生的對棧空間的影響
  • 最好:O(logn)
  • 最壞:O(n)
  • 平均:O(logn)
  • 穩定性 不穩定 比較和交換是跳躍進行的

代碼實現

import java.util.Arrays;
import java.util.Random;

/**
 * QuickSort
 * 1.對一個未排序序列,假設從該序列中的元素中取一個基準值pivotkey,將<pivotkey放左邊 >pivotkey放右邊
 * 2.接着以該k爲中間,左右兩邊的分割做爲新的序列,從新進行1操做
 * <p>
 * 快排由於用到了遞歸操做,因此在簡單排序中性能不如直接插入排序
 * 而在大量數據排序時,遞歸產生的性能影響對於算法的總體性能優點能夠忽略
 * <p>
 * 時間複雜度分析:
 * 最壞狀況:待排序爲正序或逆序,這樣每次分割後的子序列一個之比上一次序列少一個元素,一個爲空
 * 如 1 2 3 4 5 pivotkey=1;分割後一個序列爲 2 3 4 5 一個爲空
 * 最終O(n^2)
 * 最好狀況:每一次分割都能平分,很均勻 O(n*logn)
 * 平均狀況:O(n*logn) 數學概括法
 * 空間複雜度:主要有地櫃而產生的對棧空間的影響
 * 最好:O(logn)
 * 最壞:O(n)
 * 平均:O(logn)
 * 穩定性 不穩定 比較和交換是跳躍進行的
 * <p>
 * 如何合理基準值pivotkey
 * 該值的取值對該算法有至關影響,若pivotkey取到了最大或最小,都會增長算法複雜度,影響性能
 * 1.隨機選取,在待排序列中隨機選取,以下降取到最大或最小值的機率
 * 2.三數取中,在待排序列的左端,中間,右端去三個值選取中位數,節省隨機數產生的時間開銷,以下降取到最大或最小值的機率
 * 三數取中時,比較的同時應將三個元素按中間,小,大的順序從新排好位置
 * 3.九數取中,三次取樣,每次取三個數,取它們的中位數,再取三個中位數的中位數
 */

public class QuickSort {
    public static void main(String[] args) {
        int[] a = new int[10];
        boolean flag = true;
        //random array
        for (int i = 0; i < a.length; i++) {
            Random rd = new Random();
            a[i] = rd.nextInt(10);
        }

        System.out.println("Random Array :");
        System.out.println(Arrays.toString(a));
        System.out.println();
        System.out.println("Quick Sort :");

        //快速排序開始
        quickSort(a, 0, a.length - 1);

        System.out.println(Arrays.toString(a));
    }

    /**
     * @param a
     * @param low
     * @param high
     */

    public static void quickSort(int[] a, int low, int high) {
        //該值定義了從哪一個位置開始分割序列
        int pivot;
        //當high-low大於某一值時適合快速排序
        //if ((high - low) >MAX_LENGTH_INSERT_SORT) 該值取7或50
        if (low < high) {
            //partition方法對序列進行排序
            pivot = partition(a, low, high);
            //分割兩個序列繼續進行快排操做
            quickSort(a, low, pivot - 1);
            quickSort(a, pivot + 1, high);
        }
    }

    /**
     * @param a
     * @param low
     * @param high
     * @return
     */

    public static int partition(int[] a, int low, int high) {
        //取每一個序列的第一個值做爲基準值
        int pivotkey = a[low];
        while (low < high) {
            //從序列的右邊開始往左遍歷,直到找到小於基準值的元素
            while (high > low && a[high] >= pivotkey) {
                high--;
            }
            //將元素直接賦予給左邊第一個,即pivotkey所在的位置
            a[low] = a[high];
            //a[high] = pivotkey;
            //從序列的左邊邊開始往右遍歷,直到找到大於基準值的元素
            while (high > low && a[low] <= pivotkey) {
                low++;
            }
            //此時的a[high]<pivotkey,已經被賦予到左邊,因此能夠將元素賦予給a[high]
            a[high] = a[low];
            //a[low] = pivotkey;


        }
        //最後的low是基準值所在的位置
        a[low] = pivotkey;
        return low;
    }


}
複製代碼

如何合理取基準值pivotkey

  • 該值的取值對該算法有至關影響,若pivotkey取到了最大或最小,都會增長算法複雜度,影響性能。
  • 隨機選取,在待排序列中隨機選取,以下降取到最大或最小值的機率。
  • 三數取中,在待排序列的左端,中間,右端去三個值選取中位數,節省隨機數產生的時間開銷,以下降取到最大或最小值的機率。
    三數取中時,比較的同時應將三個元素按中間,小,大的順序從新排好位置。
  • 九數取中,三次取樣,每次取三個數,取它們的中位數,再取三個中位數的中位數。

參考

GeeksforGeeks:https://www.geeksforgeeks.org/quick-sort/數據結構

十大經典排序算法:https://www.cnblogs.com/onepixel/articles/7674659.htmlapp

《大話數據結構》:https://book.douban.com/subject/6424904/dom

相關文章
相關標籤/搜索