最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JAVA十大排序算法之快速排序詳解

 更新時(shí)間:2021年08月23日 10:32:13   作者:阿粵Ayue  
這篇文章主要介紹了java中的快速排序,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

快速排序

快速排序是對冒泡排序的一種改進(jìn),也是采用分治法的一個(gè)典型的應(yīng)用。JDK中Arrays的sort()方法,具體的排序細(xì)節(jié)就是使用快速排序?qū)崿F(xiàn)的。

從數(shù)組中任意選取一個(gè)數(shù)據(jù)(比如數(shù)組的第一個(gè)數(shù)或最后一個(gè)數(shù))作為關(guān)鍵數(shù)據(jù),我們稱為基準(zhǔn)數(shù)(pivot,或中軸數(shù)),然后將所有比它小的數(shù)都放到它前面,所有比它大的數(shù)都放到它后面,這個(gè)過程稱為一趟快速排序,也稱為分區(qū)(partition)操作。

問題

若給定一個(gè)無序數(shù)組 [8, 5, 6, 4, 3, 1, 7, 2],并指定一個(gè)數(shù)為基準(zhǔn),拆分?jǐn)?shù)組使得左側(cè)的數(shù)都小于等于它 ,右側(cè)的數(shù)都大于它。

基準(zhǔn)的選取最優(yōu)的情況是基準(zhǔn)值剛好取在無序區(qū)數(shù)值的中位數(shù),這樣能夠最大效率地讓兩邊排序,同時(shí)最大地減少遞歸劃分的次數(shù),但是一般很難做到最優(yōu)?;鶞?zhǔn)的選取一般有三種方式:

  • 選取數(shù)組的第一個(gè)元素
  • 選取數(shù)組的最后一個(gè)元素
  • 以及選取第一個(gè)、最后一個(gè)以及中間的元素的中位數(shù)(如4 5 6 7, 第一個(gè)4, 最后一個(gè)7, 中間的為5, 這三個(gè)數(shù)的中位數(shù)為5, 所以選擇5作為基準(zhǔn))。

思路

  • 隨機(jī)選擇數(shù)組的一個(gè)元素,比如 6 為基準(zhǔn),拆分?jǐn)?shù)組同時(shí)引入一個(gè)初始指針,也叫分區(qū)指示器,初始指針指向 -1
  • 將數(shù)組中的元素和基準(zhǔn)數(shù)遍歷比較
  • 若當(dāng)前元素大于基準(zhǔn)數(shù),不做任何變化
  • 若當(dāng)前元素小于等于基準(zhǔn)數(shù)時(shí),分割指示器右移一位,同時(shí)
    • 當(dāng)前元素下標(biāo)小于等于分區(qū)指示器時(shí),當(dāng)前元素保持不動(dòng)
    • 當(dāng)前元素下標(biāo)大于分區(qū)指示器時(shí),當(dāng)前元素和分區(qū)指示器所指元素交換

快速排序

荷蘭國旗問題

荷蘭的國旗是由紅白藍(lán)三種顏色構(gòu)成,如圖:

若現(xiàn)在給一個(gè)隨機(jī)的圖形,如下:

image-20210803151023780

把這些條紋按照顏色排好,紅色的在上半部分,白色的在中間部分,藍(lán)色的在下半部分,這類問題稱作荷蘭國旗問題。

對應(yīng)leetcode:顏色分類

給定一個(gè)包含紅色、白色和藍(lán)色,一共 n 個(gè)元素的數(shù)組,原地對它們進(jìn)行排序,使得相同顏色的元素相鄰,并按照紅色、白色、藍(lán)色順序排列。

分析:

假如給定一個(gè)數(shù)組[8, 3, 6, 2, 5, 1, 7, 5],做如下操作:

1.隨機(jī)選擇數(shù)組的一個(gè)元素,比如 5 為基準(zhǔn),拆分?jǐn)?shù)組同時(shí)引入一個(gè)左分區(qū)指示器,指向 -1,右分區(qū)指示器指向基準(zhǔn)數(shù)(注:此時(shí)的基準(zhǔn)數(shù)為尾元素)

2.若當(dāng)前元素大于基準(zhǔn)數(shù),右分區(qū)指示器左移一位,當(dāng)前元素和右分區(qū)指示器所指元素交換,

索引保持不變

3.若當(dāng)前元素小于等于基準(zhǔn)數(shù)時(shí),左分區(qū)指示器右移一位,索引右移

  • 當(dāng)前元素大于等于左分區(qū)指示器所指元素,當(dāng)前元素保持不動(dòng)
  • 當(dāng)前元素小于左分區(qū)指示器所指元素,交換

簡單來說就是,左分區(qū)指示器向右移動(dòng)的過程中,如果遇到大于或等于基準(zhǔn)數(shù)時(shí),則停止移動(dòng),右分區(qū)指示器向左移動(dòng)的過程中,如果遇到小于或等于主元的元素則停止移動(dòng)。這種操作也叫雙向快速排序。

345345

代碼實(shí)現(xiàn)

public class QuickSort {
    public static final int[] ARRAY = {8, 5, 6, 4, 3, 1, 7, 2};
    public static final int[] ARRAY2 = {8, 3, 6, 2, 5, 1, 7, 5};
    private static int[] sort(int[] array, int left, int right) {
        if (array.length < 1 || left > right) return null;
        //拆分
        int partitionIndex = partition(array, left, right);
        //遞歸
        if (partitionIndex > left) {
            sort(array, left, partitionIndex - 1);
        }
        if (partitionIndex < right) {
            sort(array, partitionIndex + 1, right);
        }
        return array;
    }
    /**
     * 分區(qū)快排操作
     *
     * @param array 原數(shù)組
     * @param left  左側(cè)頭索引
     * @param right 右側(cè)尾索引
     * @return 分區(qū)指示器  最后指向基準(zhǔn)數(shù)
     */
    public static int partition(int[] array, int left, int right) {
        //基準(zhǔn)數(shù)下標(biāo)---隨機(jī)方式取值,也就是數(shù)組的長度隨機(jī)1-8之間
        int pivot = (int) (left + Math.random() * (right - left + 1));
        //分區(qū)指示器索引
        int partitionIndex = left - 1;
        //基準(zhǔn)數(shù)和尾部元素交換
        swap(array, pivot, right);
        //按照規(guī)定,如果當(dāng)前元素大于基準(zhǔn)數(shù)不做任何操作;
        //小于基準(zhǔn)數(shù),分區(qū)指示器右移,且當(dāng)前元素的索引大于分區(qū)指示器,交換
        for (int i = left; i <= right; i++) {
            if (array[i] <= array[right]) {//當(dāng)前元素小于等于基準(zhǔn)數(shù)
                partitionIndex++;
                if (i > partitionIndex) {//當(dāng)前元素的索引大于分區(qū)指示器
                    //交換
                    swap(array, i, partitionIndex);
                }
            }
        }
        return partitionIndex;
    }
    /**
     * 雙向掃描排序
     */
    public static int partitionTwoWay(int[] array, int left, int right) {
        //基準(zhǔn)數(shù)
        int pivot = array[right];
        //左分區(qū)指示器索引
        int leftIndex = left - 1;
        //右分區(qū)指示器索引
        int rightIndex = right;
        //索引
        int index = left;
        while (index < rightIndex) {
            //若當(dāng)前元素大于基準(zhǔn)數(shù),右分區(qū)指示器左移一位,當(dāng)前元素和右分區(qū)指示器所指元素交換,索引保持不變
            if (array[index] > pivot) {
                swap(array, index, --rightIndex);
            } else if (array[index] <= pivot) {//當(dāng)前元素小于等于基準(zhǔn)數(shù)時(shí),左分割指示器右移一位,索引右移
                leftIndex++;
                index++;
                //當(dāng)前元素小于等于左分區(qū)指示器所指元素,交換
                if (array[index] < array[leftIndex]) {
                    swap(array, index, leftIndex);
                }
            }
        }
        //索引和 L 指向同一個(gè)元素
        swap(array, right, rightIndex);
        return 1;
    }
    //交換
    private static void swap(int[] array, int i, int j) {
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }

    public static void print(int[] array) {
        for (int i : array) {
            System.out.print(i + "  ");
        }
        System.out.println("");
    }

    public static void main(String[] args) {
        print(ARRAY);
        System.out.println("============================================");
        print(sort(ARRAY, 0, ARRAY.length - 1));
        System.out.println("====================雙向排序==================");
        print(ARRAY2);
        System.out.println("============================================");
        print(sort(ARRAY2, 0, ARRAY2.length - 1));
    }
}

時(shí)間復(fù)雜度

在拆分?jǐn)?shù)組的時(shí)候可能會(huì)出現(xiàn)一種極端的情況,每次拆分的時(shí)候,基準(zhǔn)數(shù)左邊的元素個(gè)數(shù)都為0,而右邊都為n-1個(gè)。這個(gè)時(shí)候,就需要拆分n次了。而每次拆分整理的時(shí)間復(fù)雜度為O(n),所以最壞的時(shí)間復(fù)雜度為O(n2)。什么意思?舉個(gè)簡單例子:

在不知道初始序列已經(jīng)有序的情況下進(jìn)行排序,第1趟排序經(jīng)過n-1次比較后,將第1個(gè)元素仍然定在原來的位置上,并得到一個(gè)長度為n-1的子序列;第2趟排序經(jīng)過n-2次比較后,將第2個(gè)元素確定在它原來的位置上,又得到一個(gè)長度為n-2的子序列;以此類推,最終總的比較次數(shù):

C(n) = (n-1) + (n-2) + … + 1 = n(n-1)/2

所以最壞的情況下,快速排序的時(shí)間復(fù)雜度為O(n^2)

而最好的情況就是每次拆分都能夠從數(shù)組的中間拆分,這樣拆分logn次就行了,此時(shí)的時(shí)間復(fù)雜度為O(nlogn)。

而平均時(shí)間復(fù)雜度,則是假設(shè)每次基準(zhǔn)數(shù)隨機(jī),最后算出來的時(shí)間復(fù)雜度為O(nlogn)

參考:快速排序的時(shí)間復(fù)雜度與空間復(fù)雜度

算法穩(wěn)定性

通過上面的分析可以知道,在隨機(jī)取基準(zhǔn)數(shù)的時(shí)候,數(shù)據(jù)是可能會(huì)發(fā)生變化的,所以快速排序有不是穩(wěn)定的情況。

總結(jié)

本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • java異步編程CompletableFuture使用示例詳解

    java異步編程CompletableFuture使用示例詳解

    這篇文章主要為大家介紹了java異步編程CompletableFuture使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • SpringBoot org.springframework.beans.factory.UnsatisfiedDependencyException依賴注入異常

    SpringBoot org.springframework.beans.factory.Unsatisfie

    本文主要介紹了SpringBoot org.springframework.beans.factory.UnsatisfiedDependencyException依賴注入異常,文中通過示例代碼介紹的很詳細(xì),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-02-02
  • 解決mybatis使用foreach批量insert異常的問題

    解決mybatis使用foreach批量insert異常的問題

    這篇文章主要介紹了解決mybatis使用foreach批量insert異常的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • 一篇文章帶你入門java算術(shù)運(yùn)算符(加減乘除余,字符連接)

    一篇文章帶你入門java算術(shù)運(yùn)算符(加減乘除余,字符連接)

    這篇文章主要介紹了Java基本數(shù)據(jù)類型和運(yùn)算符,結(jié)合實(shí)例形式詳細(xì)分析了java基本數(shù)據(jù)類型、數(shù)據(jù)類型轉(zhuǎn)換、算術(shù)運(yùn)算符、邏輯運(yùn)算符等相關(guān)原理與操作技巧,需要的朋友可以參考下
    2021-08-08
  • Java HashMap 如何正確遍歷并刪除元素的方法小結(jié)

    Java HashMap 如何正確遍歷并刪除元素的方法小結(jié)

    這篇文章主要介紹了Java HashMap 如何正確遍歷并刪除元素的方法小結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • JeecgBoot框架升級至Spring?Boot3的實(shí)戰(zhàn)步驟

    JeecgBoot框架升級至Spring?Boot3的實(shí)戰(zhàn)步驟

    本文主要介紹了JeecgBoot框架升級至Spring?Boot3的實(shí)戰(zhàn)步驟,從?2.7.10升級到3.1.5有以下幾個(gè)點(diǎn)需要注意,下面就來詳細(xì)的介紹一下,感興趣的可以了解一下
    2024-04-04
  • Spring實(shí)戰(zhàn)之抽象Bean和子Bean定義與用法示例

    Spring實(shí)戰(zhàn)之抽象Bean和子Bean定義與用法示例

    這篇文章主要介紹了Spring實(shí)戰(zhàn)之抽象Bean和子Bean定義與用法,結(jié)合實(shí)例形式分析了Spring抽象Bean和子Bean相關(guān)配置、定義與使用操作技巧,需要的朋友可以參考下
    2019-11-11
  • ScheduledThreadPoolExecutor巨坑解決

    ScheduledThreadPoolExecutor巨坑解決

    這篇文章主要為大家介紹了使用ScheduledThreadPoolExecutor遇到的巨坑解決示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • Java這個(gè)名字的來歷與優(yōu)勢

    Java這個(gè)名字的來歷與優(yōu)勢

    Java是Sun公司開發(fā)的一種編程語言,Sun公司最初的方向是讓Java來開發(fā)一些電器裝置程序,Java名字的由來,實(shí)際上是一個(gè)有趣的故事。
    2014-10-10
  • Java讀寫Windows共享文件夾的方法實(shí)例

    Java讀寫Windows共享文件夾的方法實(shí)例

    本篇文章主要介紹了Java讀寫Windows共享文件夾的方法實(shí)例,具有一定的參考價(jià)值,有興趣的同學(xué)可以了解一下。
    2016-11-11

最新評論

巴彦县| 通辽市| 招远市| 和林格尔县| 桐庐县| 康平县| 桂东县| 永泰县| 赣榆县| 城固县| 齐齐哈尔市| 六盘水市| 揭东县| 房产| 武陟县| 阿勒泰市| 枝江市| 饶阳县| 上蔡县| 乌海市| 句容市| 南漳县| 双峰县| 平远县| 织金县| 内江市| 蒲城县| 康乐县| 永登县| 聂拉木县| 安多县| 华宁县| 青神县| 广安市| 龙泉市| 棋牌| 舟曲县| 罗田县| 通江县| 伊通| 康乐县|