快速排序算法詳(xiang)解
時間(jian):2018-12-26 來源:華(hua)清遠見
快速排(pai)(pai)序(xu)(Quick Sort)是對冒泡排(pai)(pai)序(xu)的(de)一種改進(jin)。由C. A. R. Hoare在(zai)1962年提出,其(qi)(qi)基(ji)本思(si)想是選取一個(ge)(ge)記錄(lu)作(zuo)為樞軸,經(jing)過一趟(tang)排(pai)(pai)序(xu),將整(zheng)(zheng)段(duan)序(xu)列分(fen)為兩個(ge)(ge)部(bu)分(fen),其(qi)(qi)中一部(bu)分(fen)的(de)值都小于(yu)樞軸,另一部(bu)分(fen)都大于(yu)樞軸。然后繼續對這兩部(bu)分(fen)繼續進(jin)行排(pai)(pai)序(xu),從而使整(zheng)(zheng)個(ge)(ge)序(xu)列達(da)到有序(xu)。
1.基(ji)本思想(xiang):
例如對于一個待(dai)排序的(de)源數(shu)組arr = { 4,1,3,2,7,6,8}。

我們可(ke)以(yi)隨便選(xuan)一個(ge)元素(su),假(jia)如我們選(xuan)數組的第一個(ge)元素(su)吧(ba),我們把這個(ge)元素(su)稱之為“主元”吧(ba)。

然后將(jiang)大于(yu)(yu)(yu)或等于(yu)(yu)(yu)主(zhu)元(yuan)的元(yuan)素(su)放在右邊(bian),把小(xiao)于(yu)(yu)(yu)或等于(yu)(yu)(yu)主(zhu)元(yuan)的元(yuan)素(su)放在左邊(bian)。

通過(guo)這種規則的調整(zheng)之(zhi)后,左邊(bian)的元(yuan)素(su)都(dou)小于(yu)(yu)或等于(yu)(yu)主元(yuan),右(you)邊(bian)的元(yuan)素(su)都(dou)大于(yu)(yu)或等于(yu)(yu)主元(yuan),很顯然(ran),此時主元(yuan)所處的位置(zhi)(zhi),是一個有(you)序的位置(zhi)(zhi),即(ji)主元(yuan)已經處于(yu)(yu)排好(hao)序的位置(zhi)(zhi)了。
主元(yuan)把數組分(fen)(fen)成了兩半部(bu)分(fen)(fen)。把一個大的(de)數組通過主元(yuan)分(fen)(fen)割成兩小部(bu)分(fen)(fen)的(de)這(zhe)個操作(zuo),我們也稱之(zhi)為分(fen)(fen)割操作(zuo)(partition)。
接下(xia)來,我們通過遞(di)(di)歸的(de)方(fang)式(shi),對左(zuo)右兩部分采(cai)取同樣的(de)方(fang)式(shi),每次選取一個主(zhu)元(yuan)(yuan)元(yuan)(yuan)素(su)(su),使他處于有序的(de)位(wei)置。當然是遞(di)(di)歸到子數組只有一個元(yuan)(yuan)素(su)(su)或(huo)者0個元(yuan)(yuan)素(su)(su)了,遞(di)(di)歸結束。

代碼:quick_sort 是(shi)快速排序的(de)算法,partion函數是(shi)對于數組(zu)的(de)分(fen)割操作,分(fen)割操作有很多種方法,我這(zhe)里列舉三種。

2.分割操作
2.1 單向調整(zheng)
選(xuan)最后一(yi)個為(wei)主(zhu)元,假設數組arr的范圍為(wei)[left, right],即起始(shi)下(xia)標為(wei)left,末(mo)尾下(xia)標為(wei)right。源數組如下(xia)

然后(hou)可以用(yong)一(yi)個下標(biao)(biao) i 指向 left,即(ji) i = left ;用(yong)一(yi)個下標(biao)(biao) j 也指向left,即(ji)j = left

接(jie)下(xia)來 j 從左向右遍(bian)歷,遍(bian)歷的(de)(de)范圍為(wei) [left, right-1] ,遍(bian)歷的(de)(de)過程(cheng)中,如果遇到比主元(yuan)(yuan)小的(de)(de)元(yuan)(yuan)素,則把該元(yuan)(yuan)素與 i 指向的(de)(de)元(yuan)(yuan)素交(jiao)換,并且 i = i +1

當j指向1時,1比4小,此時把i和j指向的元素交換,之后 i++。

就這樣讓j一直(zhi)向右(you)遍歷,直(zhi)到 j = right

遍(bian)歷完成之(zhi)后,把 i 指向(xiang)的(de)元素(su)與主(zhu)元進行交換,交換之(zhi)后,i 左邊(bian)的(de)元素(su)一(yi)定小于(yu)主(zhu)元,而(er) i 右邊(bian)的(de)元素(su)一(yi)定大于(yu)或等于(yu)主(zhu)元。這樣,就 i 完成了(le)一(yi)次分割了(le)。

代碼如下:

2.2 雙向調(diao)整
源數組如下:

然(ran)后(hou)用(yong)令變量(liang)i = left + 1,j = right。然(ran)后(hou)讓(rang) i 和 j 從數組(zu)的(de)兩邊(bian)向中間掃描。

i 向右遍歷的(de)過(guo)程中,如(ru)果遇(yu)到大(da)于(yu)或(huo)等于(yu)主元(yuan)的(de)元(yuan)素時,則停止(zhi)移動,j向左(zuo)遍歷的(de)過(guo)程中,如(ru)果遇(yu)到小(xiao)于(yu)或(huo)等于(yu)主元(yuan)的(de)元(yuan)素則停止(zhi)移動。

當(dang)i和j都停止移(yi)動(dong)時,如果這(zhe)時i < j,則交換(huan) i, j 所指向(xiang)的(de)元素。此時 i < j,交換(huan)8和3

然后繼(ji)續向中間遍(bian)歷,直到i >= j。

此時i >= j,分割結束。最后在把主元(yuan)與 j 指向(xiang)的(de)元(yuan)素交換(huan)。

這個(ge)時(shi)候,j 左(zuo)邊(bian)的元(yuan)素(su)一定小于(yu)或(huo)等于(yu)主元(yuan),而右邊(bian)則(ze)大于(yu)或(huo)等于(yu)主元(yuan)。
到此,分割調整完畢。
代碼如下:

2.3 挖坑法
1.選取(qu)一個(ge)(ge)關(guan)鍵字(zi)(key)作(zuo)為主(zhu)元,一般取(qu)整組(zu)記錄的第一個(ge)(ge)數/最(zui)后一個(ge)(ge),這里采用選取(qu)序(xu)列最(zui)后一個(ge)(ge)數為樞軸,也(ye)是(shi)初(chu)始的坑位(wei)。
2.設置兩個變量left = 0;right = N - 1;
3.從(cong)left一(yi)直向(xiang)后(hou)走(zou),直到(dao)找到(dao)一(yi)個大于key的值(zhi),然后(hou)將該數放入坑(keng)中,坑(keng)位變成了(le)array[left]。
4.right一直向(xiang)前走,直到(dao)找到(dao)一個小于(yu)key的值,然(ran)后將該數放入坑中,坑位變(bian)成(cheng)了array[right]。
5.重(zhong)復3和(he)(he)4的步驟,直到(dao)left和(he)(he)right相遇,然后(hou)將key放入最后(hou)一個坑位。

代碼如下:


