快速排序圖解
關注:92 發布時間:2021-06-22 12:19:57
之前我們在交換類排序中引入了冒泡排序,這次引入了另一種交換類排序,叫做快速排序。快速排序的優點是原地排序,不占用額外空間,時間復雜度為o(nlogn)。
當然對于快速排序也有缺點。對于包含大量重復元素的數組排序效率非常低,時間復雜度會降低到o(n ^ 2)。此時,我們需要使用改進的快速排序-雙向快速排序。在雙向快速排序的基礎上,進一步優化了三向快速排序。
快速排序
快速排序的基本思想是通過一遍排序將待排序的數據分成兩個獨立的部分,其中一部分的所有數據都小于另一部分的所有數據,然后按照這種方法分別對這兩部分數據進行快速排序,整個排序過程可以遞歸進行,使整個數據成為有序序列。
快速排序步驟如下:
1.以第一個元素為分界點,用l指向它。
2.遍歷右邊的元素。在遍歷的過程中,我們排列數組,有的小于v,有的大于v,用j指向小于v和大于v的分界點,用i指向當前訪問的元素e,此時數組arr[l 1…j]v,arr [j 1 … i-1] v。
3.如果ev,直接在大于v的部分后面合并e,然后我繼續比較下面的元素。
4.如果ev,把e移到j指向的元素的后面元素,然后j,然后我繼續比較后面的元素。
5.這樣遍歷整個數組一次。遍歷后,數組分為三部分,左邊部分為v,中間部分為v,右邊部分為v。
6.比較后我們把l指向的元素和j指向的元素進行交換,這樣元素v就很快排序了。v的左邊元素小于v,右邊元素大于v。
現在我們用上面的方法快速排序數組[2,1,4,3,7,8,5,6]。下圖顯示了快速排序的整個過程:
快速排序代碼:
公共靜態無效排序(可比[] arr) {
int n=arr.length
sort(arr,0,n1);
}
//遞歸使用快速排序對arr的范圍進行排序[l…r]
私有靜態空排序(可比[] arr,int l,int r) {
if (l=r) {
返回;
}
//分區arr[l…r]并返回p,這樣arr[l…p-1]arr[p];arr[p 1…r] arr[p]
int p=partition(arr,l,r);
排序(arr,l,p1);
sort(arr,p 1,r);
}
私有靜態int分區(可比[] arr,int l,int r) {
//比較左邊的元素用作校準點
可比v=arr[l];
int j=l;
for(int i=l 1;i=r;i ) {
if (arr[i]。compareto(v) 0)
swap(arr,j 1,i);
j .
}
}
swap(arr,l,j);
返回j;
}
優化快速排序
經過上面的介紹,我們可以發現快速排序并不能保證每個分割都有相同大小的子陣,所以可能一邊小一邊大。對于有序數組,快速排序的時間復雜度變成o(n ^ 2),相當于樹退化成鏈表。下圖顯示了這一變化:
上面,我們使用左邊的第一個元素作為校準元素。現在我們隨機選擇一個元素作為校準元素。此時第一次選擇第一個元素的概率為1/n,第二個元素為1/n-1。以此類推,在出現之前退化成鏈表的概率是1/n(n-1)(n-2)…。當n較大時,這個概率幾乎為零。
另一個優化是對小規模數組使用插入排序,因為遞歸會使小規模問題中的方法調用過于頻繁,并且插入排序對于小規模數組非常快。
優化的快速排序代碼:
公共靜態無效排序(可比[] arr) {
int n=arr.length
sort(arr,0,n1);
}
//賀盛文賀盛文,-什么停止[l.r]阿云阿云阿云阿云阿云阿云阿云
私有靜態void排序(相當于[] arr,int l,int r)}
//云娥與云娥,云娥與云娥
如果(rl=15)}
insertonstart。sort(arr、l、r);
返回;
}
//-什么停止[l.r]阿悅分割區誒誒喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲喲,阿忠p,你知道嗎?僧兒頁:1:停止[p1.r]停止[p]
int p=分區(arr、l、r);
輸出(arr,l,p-1);
(經常預算):
}
專用靜態(同internationalorganizations)國際組織部件
(可比[] arr,int l,int r) {
//在arr[l…r]范圍內隨機選擇一個值作為校準點軸心
swap(arr,l,(int)(math . random*(rl ^ 1))l);
可比v=arr[l];
int j=l;
for(int i=l 1;i=r;i ) {
if (arr[i]。compareto(v) 0)
swap(arr,j 1,i);
j .
}
}
swap(arr,l,j);
返回j;
}
雙向快速排序
對于包含大量重復元素的數組,上面的快速排序效率很低,因為在我們上面的判斷中,如果元素小于v,那么元素就放在v部分,如果元素大于等于v,那么就放在v部分。這時如果數組中有大量重復的元素,v部分會變得很長,導致左右兩邊不平衡,性能降低。
雙向快速排序的步驟如下:
1.把v和v放在數組的兩端,用i指向v的下一個元素,用j指向v的前一個元素。
2.從i向后遍歷,如果遍歷的元素ev繼續向后遍歷,直到遍歷的元素e=v,那么停止遍歷。從j開始向前遍歷,如果遍歷的元素為ev,繼續向前遍歷,直到遍歷的元素e=v,然后停止遍歷。
3.交換一下我指向的元素和j指向的元素,然后我,j繼續比較下一個。
雙向快速排序代碼:
公共靜態無效排序(可比[] arr) {
int n=arr.length
sort(arr,0,n1);
}
私有靜態空排序(可比[] arr,int l,int r) {
//對于小規模數組,使用插入排序
if(rl=15){
insertionsort.sort(arr,l,r);
返回;
}
int p=partition(arr,l,r);
排序(arr,l,p1);
sort(arr,p 1,r);
}
私有靜態int分區(可比[] arr,int l,int r) {
//在arr[l…r]范圍內隨機選擇一個值作為校準點軸心
swap(arr,l,(int)(math . random*(rl ^ 1))l);
可比v=arr[l];
int i=l 1,j=r;
while (true) {
//注意這里的邊界,arr[i]。compareto(v) 0,不能是arr[i]。compareto(v)=0
//如果不加等號,此時會退出while循環,也就是交換i和j的值,這樣對于一個包含大量相同元素的數組,交換兩邊相等的數據,可以在一定程度上保證兩路的數據平衡。
//從i向后遍歷,如果遍歷的元素ev,繼續向后遍歷,直到遍歷的元素e=v,然后停止遍歷
while (i=r arr[i]。compareto(v) 0)
i;
}
//從j開始向前遍歷,如果遍歷的元素為ev,繼續向前遍歷,直到遍歷的元素e=v,然后停止遍歷
while(j=l ^ 1 arr[j]。compareto(v) 0)
j ;
}
if (i=j) {
打破;
}
swap(arr,i,j);
i;
j ;
}
//此時j指向的元素是數組中小于v的比較后一個元素,i指向的元素是數組中大于v的第一個元素。
swap(arr,l,j);
返回j;
}
三向快速排序
三向快速排序的步驟如下:
1.在雙向快速排序的基礎上,我們將等于v的元素作為單一部分。lt指向小于v部分的比較后一個元素,gt指向大于v部分的第一個元素。
2.從i向后遍歷,如果遍歷的元素e=v,e直接合并到=v部分,然后i繼續遍歷。如果你遍歷元素ev,交換e部分的第一個元素和=v(lt 1指向的元素),然后lt,我繼續遍歷。如果遍歷的元素ev,則交換e和v的前一個元素(gt-1指向的元素),然后gt ,但此時不需要改變i,因為i位置的元素與gt位置之前的空白元素交換。
3.遍歷之后,i=gt,然后用lt-pointing元素交換l-pointing元素。
4.在v形零件和v形零件上執行上述操作。
三向快速排序相對于雙向快速排序的優勢在于,減少了重復元素的比較操作,因為重復元素在一次排序中已經被排列為單一部分,然后只需要對不等于重復元素的其他元素進行排序。
三向快速排序代碼:
公共靜態無效排序(可比[] arr) {
int n=arr.length
sort(arr,0,n1);
}
私有靜態空排序(可比[] arr,int l,int r) {
//對于小規模數組,使用插入排序
if(rl=15){
insertionsort.sort(arr,l,r);
返回;
}
//在arr[l…r]范圍內隨機選擇一個值作為校準點軸心
swap(arr,l,(int)(math . random*(rl ^ 1))l);
可比v=arr[l];
int lt=l;//arr[l 1…lt] v
int gt=r 1;//arr[gt…r] v
int i=l 1;//arr[lt 1…i)=v
while (i gt) {
if (arr[i]。compareto(v) 0)
swap(arr,i,lt 1);
i;
lt。
} else if (arr[i]。compareto(v) 0)
互換(arr,i,gt1);
gt ;
} else { //arr[i]==v
i;
}
}
互換(arr,l,lt);
排序(arr,l,lt1);
sort(arr,gt,r);
}
摘要
本文介紹了快速排序、快速排序的優化、雙向快速排序和三向快速排序。
為了快速排序,我們需要選擇合適的校準點,使校準點的兩側平衡;當在快速排序中遞歸到小數組時,我們可以用插入排序來代替遞歸,以減少不必要的開銷。
對于雙向快速排序和三向快速排序,我們在數組中使用了大量重復的元素。
比較后,建議jdk底部的排序使用插入排序 雙路快速排序
合并和排序的組合。
上一篇:平安專享額度怎么用?
下一篇:格力移動空調效果怎么樣
猜你喜歡
-
這將是十年來最好的創富時機76人支持
過去十年見證了中國經濟的巨大變化。從2009年開始,經濟學家開始預測,明年將是中國經濟發展最困難的一年。隨著移動互聯網的逐漸普及,人們的生活方式發生了巨大的變化。與此同時…
-
華為手機安全模式怎么解除73人支持
手機安全模式是手機系統中的一種特殊模式,其原理類似于windows安全模式。手機的安全模式只加載系統的基本功能和一些預設的應用,其他用戶安裝的第三方應用無法在安全模式下顯…
-
木三事件是怎么回事77人支持
網上有很多匪夷所思的靈異事件,有些是網友的親身經歷,有些沒有得到證實,但被網友的口碑渲染得有點嚇人。三目事件和當年的左陽事件類似,但是后來她沒有再出現在網絡上,大家都很擔…
-
美柚和大姨嗎哪個好用?87人支持
市面上誕生了很多女性健康管理app,但最終deus ex和美柚占據了主要市場份額。未來女性健康管理領域的“霸主”是誰?是“吞并”還是“共存”?目前似乎沒有定論。初期社區戰:美柚…
-
工勤崗位是什么意思112人支持
事業單位分為管理崗位、專業技術崗位和工業后勤崗位。管理崗位和專業技術崗位是干部,工業和后勤崗位是工人。所有政府機關和事業單位都要求每個報名的人都必須參加考試。所以…
-
目前筆記本電腦哪款好93人支持
題主沒有給出買電腦的目的和預算,只能說說個人經歷。因為是工作需要,主要用于辦公需要,所以我現在用的是聯想thinkpad x1 carbon(不是廣告,這個型號我用了好幾年了),也推薦這個…
-
抖音怎么設置不讓別人保存我的視頻63人支持
注冊tik tok賬戶時,開發者許可協議中明確規定,當您發布視頻時,默認情況下,每個人都可以在未經您授權的情況下轉載和使用它。盡量有辦法。您可以在視頻中添加水印。例如:“未經授…
-
在別人眼里的“43人支持
之前認識一個合伙人,月薪八萬多,設計圖紙做的挺好。我給她的工作都是可以熟練完成的,每次完成的時間超出了我的想象。有一次請她吃飯,發現她在幾個平臺上盈利,而且是在工作之外做…
-
k40系列怎么樣31人支持
今天在小米之家體驗了紅米在線發布的最新k40系列,想說一下對你的一些感受。1.外貌方面,個人感覺幻境最好,其次是晴天和下雪天,最后是明亮和黑暗。幻想那個顏色真好看,角度不一樣,…
-
電話催收是爛工作嗎56人支持
還有其他網點或者其他工作,建議大家不要打電話催收。第一,人性的惡會在工作中被無限放大;第二,這條線的水靠電很深,賺了辛苦錢上岸可能不安全。有可能嘗試收銀行違約,但是很多電催…
-
淘寶網新手開店入門4人支持
一、注冊賬號首先,第一步一定要注冊淘寶賬號。這里按照注冊的基本操作,相信大家都能完成。但是,不能修改旺旺的名稱。在確定要做什么品類之后,旺旺的名字要和店鋪、產品、品類相…
-
天貓網店開店費用65人支持
開一家天貓旗艦店,也就是天貓最高級的店,首先要滿足天貓入駐的條件!假設你能達到天貓的入門要求,那么基本成本是多少?你可以算一下:1.天貓押金10萬!2.技術服務費3萬元!3.質檢費用100…
熱門十大品牌
- 2021年我國十大黃金品牌排行榜30998人
- 眼鏡品牌十大排行榜前10名26345人
- 十大證券公司排行榜前10名23241人
- 2021年我國雜志排行榜前10名20053人
- 我國十大雜志排行榜前10名16355人
- 2021我國十個宜居城市排行榜前11485人
- 男士褲子品牌十大排行榜前10名11185人
- 2021十大火熱電腦游戲排行榜前11056人
- 十大衛生巾品牌排行榜前十名8846人
- 我國十大襪子品牌排行榜前十名8364人