日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

快速排序 挖坑_由浅入深玩转快速排序算法

發(fā)布時(shí)間:2023/12/2 编程问答 57 豆豆
生活随笔 收集整理的這篇文章主要介紹了 快速排序 挖坑_由浅入深玩转快速排序算法 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

由淺入深玩轉(zhuǎn)快速排序算法

? ? ? 快速排序可以說(shuō)是最快的通用排序算法,它甚至被譽(yù)為20世紀(jì)科學(xué)和工程領(lǐng)域的十大算法之一。在眾多排序算法中其無(wú)論是時(shí)間復(fù)雜度還是空間復(fù)雜度都頗具優(yōu)勢(shì)。作為開(kāi)發(fā)工程師,我們很有必要了解它的思想。接下來(lái)將由在下為大家一步步分析這一偉大排序算法的原理與實(shí)現(xiàn)思路。

主要從三個(gè)方向展開(kāi)論述:

1、算法基本原理與實(shí)現(xiàn):介紹兩種常用的實(shí)現(xiàn)思路。

2、性能特點(diǎn):介紹算法高效的秘訣與其弱點(diǎn)。

3、算法優(yōu)化:介紹PHP7與Java等成熟語(yǔ)言對(duì)算法的優(yōu)化應(yīng)用

1

快速排序算法基本原理

????????快速排序是一種分治的排序算法,即將大數(shù)組拆分成小數(shù)組處理。通過(guò)一趟排序?qū)⒋艛?shù)組分成兩個(gè)子數(shù)組,使得一個(gè)子數(shù)組的元素均比另一個(gè)子數(shù)組的元素小。再分別將子數(shù)組進(jìn)行上述排序,最終使得整個(gè)數(shù)組有序。其基本實(shí)現(xiàn)可以分為以下3步:

1、選中軸(pivot):從待排序的目標(biāo)數(shù)組中挑選一個(gè)元素作為中軸元素。

2、分區(qū)(partition):把剩余的元素與中軸元素作比較,將小于等于中軸元素的放到中軸元素的左邊,將大于中軸元素的放到中軸元素的右邊。

3、 遞歸:以當(dāng)前中軸元素的位置為界,將左子數(shù)組和右子數(shù)組看成兩個(gè)新的數(shù)組并重復(fù)上述操作,直到子數(shù)組的元素個(gè)數(shù)小于等于1。

????????快速排序算法可以有多種實(shí)現(xiàn)方式,選擇不同的中軸與選擇相同的中軸時(shí)均有不同的實(shí)現(xiàn)方法。下面舉出兩個(gè)例子供大家參考,方便大家理解實(shí)現(xiàn)思路。

1.1?左右掃描,交換元素

????????下圖quickSort1是采用了此方案實(shí)現(xiàn)的快速排序的一次分區(qū)過(guò)程,待排序數(shù)組是$arr = [4, 3, 8, 1, 6, 2, 7, 5];

1.2 左右掃描,挖坑補(bǔ)坑

????????在第一個(gè)實(shí)現(xiàn)思路中,當(dāng)在左側(cè)找到大于中軸元素和在右側(cè)找到小于中軸元素的兩個(gè)元素位置時(shí),需要對(duì)兩個(gè)元素進(jìn)行交換。其中涉及到一個(gè)新的臨時(shí)變量的操作。下面的實(shí)現(xiàn)采用填坑的思路直接賦值,省去了臨時(shí)變量的讀寫(xiě)操作。

????????下圖quickSort2是采用了一端挖坑一端補(bǔ)坑的快速排序的一次分區(qū)過(guò)程,待排序數(shù)組同樣是$arr = [4, 3, 8, 1, 6, 2, 7, 5];

2

性能特點(diǎn)

快速排序之所以快速主要有兩個(gè)原因:

1、內(nèi)循環(huán)操作簡(jiǎn)潔

????????在分區(qū)方法的內(nèi)循環(huán)中僅采用遞增或遞減的索引將數(shù)組元素與一個(gè)定值作比較。并且沒(méi)有在內(nèi)循環(huán)中移動(dòng)數(shù)據(jù),很難想象在排序算法中能有比這操作更簡(jiǎn)潔的內(nèi)循環(huán)了。

2、比較次數(shù)少

????????快速排序的效率依賴于切分?jǐn)?shù)組的效果,即依賴于中軸元素的值。其最佳的情況是每次都正好將數(shù)組對(duì)半切分。在這種情況下快速排序的時(shí)間復(fù)雜度為O(Nlog2N)。而在每個(gè)子數(shù)組里面的數(shù)據(jù)也不會(huì)與其他子數(shù)組的數(shù)據(jù)做重復(fù)比較,大幅提升了效率。

????????由此我們也很容易看出快速排序的缺點(diǎn):在分區(qū)不平衡的時(shí)候可能會(huì)出現(xiàn)極低的效率。快速排序最壞情況的時(shí)間復(fù)雜度為O(N2)。

3

算法優(yōu)化

3.1 解決分區(qū)不平衡

????????由于中軸元素的選擇直接決定了快速排序的效率,為了使算法在數(shù)組逆序或?qū)⒔行虻葠毫訄?chǎng)景中都能達(dá)到高效率,我們可以采用以下辦法解決分區(qū)“一邊倒”的情況。

1、間接解決:在排序前使數(shù)組保持隨機(jī)性,即先對(duì)待排序數(shù)組進(jìn)行亂序操作,再做快速排序,降低分區(qū)不平衡的概率。

2、直接解決:采用三數(shù)取中法或三取樣切分,隨機(jī)選取中軸元素。

3.2 切換到插入排序

????????對(duì)于小數(shù)組排序,插入排序比快速排序更快。因此在排序元素?cái)?shù)量較小的數(shù)組時(shí)應(yīng)該切換到插入排序。如PHP7的sort()排序函數(shù)的實(shí)現(xiàn):在數(shù)組長(zhǎng)度為 5~16 時(shí)采用插入排序否則采用快速排序。

(https://github.com/php/php-src/blob/PHP-7.4/Zend/zend_sort.c)

3.3 三切分快速排序

????????在實(shí)際應(yīng)用中經(jīng)常會(huì)出現(xiàn)含有大量重復(fù)元素的數(shù)組,例如我們需要將大量用戶數(shù)據(jù)按VIP等級(jí)排序或按生日日期排序。此時(shí)采用上述實(shí)現(xiàn)方案的經(jīng)典快速排序則顯得有點(diǎn)笨,因?yàn)楫?dāng)一個(gè)子數(shù)組中的元素都是重復(fù)時(shí),我們的算法仍然會(huì)將它切分成更小的數(shù)組遞歸排序。在有大量重復(fù)元素的情況下,這無(wú)疑會(huì)做很多無(wú)用功,使得時(shí)間復(fù)雜度提高到平方級(jí)別(O(N2))。而三向切分快速排序,則是為此而生,專門應(yīng)對(duì)有大量重復(fù)元素?cái)?shù)組的排序情況,是一種能把時(shí)間復(fù)雜度從線性對(duì)數(shù)級(jí)別(O(Nlog2N)) 降到線性級(jí)別(O(N))的算法實(shí)現(xiàn)。

????????基本實(shí)現(xiàn)思路:從左往右掃描數(shù)組,利用三個(gè)變量$i,$j,$k把數(shù)組分成4部分。

如下圖所示:

????????分區(qū)剛開(kāi)始,選擇數(shù)組最左側(cè)的元素作為中軸元素。$i指向最左側(cè)元素,$k指向最左側(cè)元素的下一個(gè)元素,$j指向最右側(cè)的元素。

如下圖所示:

????????從左往右掃描數(shù)組,直到$k與$j相交($k > $j)。通過(guò)掃描,把未知元素按照其與中軸元素的大小關(guān)系放入不同的區(qū)間,不斷減少未知元素的數(shù)量,以完成分區(qū)。

????????當(dāng)一次掃描結(jié)束后$i和$j分別指向了【=$pivot】區(qū)間的起始和結(jié)束位置。最后分別遞歸小于中軸部分的數(shù)組和大于中軸部分的數(shù)組,即可完成排序。

????????我們對(duì)有大量重復(fù)數(shù)據(jù)的數(shù)組進(jìn)行排序,驗(yàn)證三向切分快速排序的效果。(此處的測(cè)試僅是為了體現(xiàn)算法實(shí)現(xiàn)思想的差異會(huì)出現(xiàn)不同的性能效果,并不能嚴(yán)謹(jǐn)說(shuō)明兩者的性能程度差距。)分別用1萬(wàn),10萬(wàn)和50萬(wàn)數(shù)據(jù)量的數(shù)組進(jìn)行測(cè)試對(duì)比,數(shù)據(jù)生成規(guī)則是1-10內(nèi)隨機(jī)生成,可以說(shuō)數(shù)據(jù)重復(fù)概率極高。每個(gè)情況進(jìn)行5次測(cè)試求平均值,得出以下數(shù)據(jù)表格:

????????可見(jiàn)在有大量重復(fù)數(shù)據(jù)的排序中,三向切分秒殺了經(jīng)典快速排序。表中所示在對(duì)50萬(wàn)級(jí)別的數(shù)據(jù)排序時(shí),經(jīng)典快速排序耗時(shí)高達(dá)48分鐘(等了好久才等到這個(gè)數(shù)據(jù)),而三向切分快速排序僅用了0.5秒。

????????而在重復(fù)元素較少的數(shù)組中,三向切分的性能并無(wú)優(yōu)勢(shì),相比經(jīng)典快速排序需要消耗將近2倍的時(shí)間:

????????是否有一種實(shí)現(xiàn)方式既能兼顧有大量重復(fù)元素和低重復(fù)元素?cái)?shù)組的排序呢?接下來(lái),我們看看Java中Arrays.sort()的排序?qū)崿F(xiàn)。

3.4 雙軸快速排序

在JDK1.7中給出了雙軸快速排序(DualPivotQuicksort)的思想,當(dāng)然僅靠一個(gè)排序思想無(wú)法應(yīng)對(duì)復(fù)雜的業(yè)務(wù)場(chǎng)景,為保證最高的排序效率,Java在實(shí)際排序中采用了一套相對(duì)成熟及復(fù)雜的方案,根據(jù)元素的數(shù)量及有序性采用了不同的排序方案。

????????雙軸快速排序在有大量重復(fù)元素的排序中表現(xiàn)良好,同時(shí)能兼顧大量非重復(fù)元素的數(shù)組排序,其在實(shí)現(xiàn)思路上,跟三向切分快速排序有類似之處。已經(jīng)理解了上面介紹過(guò)的三向切分,再來(lái)理解雙軸快速排序就不難了。大致實(shí)現(xiàn)思路如下圖所示:

????????完成分區(qū)后,分別對(duì)雙軸切分出來(lái)的三個(gè)區(qū)間進(jìn)行遞歸排序即可。(受限于篇幅,以上所有算法實(shí)現(xiàn)只講述思路并未貼出代碼,如感興趣的同學(xué)可以找作者要PHP版的實(shí)現(xiàn)代碼。)

總結(jié)

????????本文主要講述了快速排序的原理及實(shí)現(xiàn)思路,總結(jié)為以下三點(diǎn):

1、基本原理與實(shí)現(xiàn):可采用元素交換或挖坑補(bǔ)坑的方式實(shí)現(xiàn)快速排序。

2、算法性能特點(diǎn):

  • 快速高效的兩個(gè)原因:其一內(nèi)循環(huán)操作簡(jiǎn)潔;其二比較次數(shù)較少

  • 性能弱點(diǎn):中軸元素選擇不當(dāng)可能導(dǎo)致性能極其低下

3、算法優(yōu)化:

  • 解決分區(qū)不平衡的2種辦法

  • 對(duì)小數(shù)組排序采用插入排序

  • 對(duì)有大量重復(fù)元素的數(shù)組采用三向切分快速排序

  • JDK1.7中雙軸快速排序的實(shí)現(xiàn)思路

參考文獻(xiàn):

[1]《算法(第4版)》

[2]《QUICKSORTING - 3-WAY AND DUAL PIVOT》https://rerun.me/2013/06/13/quicksorting-3-way-and-dual-pivot/

[3]《Java中雙基準(zhǔn)快速排序方法的具體實(shí)現(xiàn)》http://www.mamicode.com/info-detail-2395124.html

排版 |川芮

總結(jié)

以上是生活随笔為你收集整理的快速排序 挖坑_由浅入深玩转快速排序算法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。