快速排序

一宴胧、partition quicksort 分治+遞歸

快速排序一次劃分算法偽代碼:

將i和j分別指向待排序列最左記錄與最右側(cè)記錄;

重復(fù)下述過程,直到i = j;

右側(cè)掃描,j--,直到a[j] ? ? ? ? ? ? ? ? ? 表示前面已經(jīng)排行

左側(cè)掃描,直到a[i]>a[j],交換,j--; ? 表示前面已經(jīng)排好

循環(huán)結(jié)束,i = j,返回i的位置.

二猛蔽、快速排序可用于求第k個(gè)最大值

用O(n)的平均時(shí)間復(fù)雜度從無序數(shù)組中尋找第k大的值.和快排一樣,這里也用到了分而治之的思想.思路是,首先對(duì)數(shù)組進(jìn)行一次Partition,得到坐標(biāo)nPos:

如果nPos+1 == k,返回array[nPos];

如果nPos+1 > k,對(duì)數(shù)組左半部分繼續(xù)進(jìn)行Partition;

如果nPos+1 < k, 對(duì)數(shù)組右半部分繼續(xù)進(jìn)行Partition.

// 利用Partition實(shí)現(xiàn)復(fù)雜度為O(n)的尋找數(shù)組中第K大的數(shù)

int GetArrayMaxK(int array[], int nStart, int nEnd, int k)

{

if (k <= 0)

{

throw;

}

int nPos = -1;

while (true)

{

nPos = Partition(array, nStart, nEnd);

if ((nPos+1) == k)

{

return array[nPos];

}else if ((nPos+1) > k)

{

nEnd = nPos - 1;

}else

{

nStart = nPos + 1;

}

}

}

三初斑、partition進(jìn)階

荷蘭國旗問題

(可以以紅白藍(lán)為數(shù)字代替,統(tǒng)計(jì)數(shù)字,重新分配)

一種思路

我們可以把數(shù)組分成三部分,前部(全部是0)冕屯,中部(全部是1)和后部(全部是2)三個(gè)部分,每一個(gè)元素(紅白藍(lán)分別對(duì)應(yīng)0拂苹、1安聘、2)必屬于其中之一。

將前部和后部各排在數(shù)組的前邊和后邊,中部自然就排好了浴韭。

設(shè)置兩個(gè)指針begin指向前部(不是按0丘喻,1,2的個(gè)數(shù)區(qū)分的前后部)的末尾的下一個(gè)元素(相當(dāng)于)(剛開始默認(rèn)前部無0念颈,所以指向第一個(gè)位置)泉粉,end指向后部開頭的前一個(gè)位置(剛開始默認(rèn)后部無2,所以指向最后一個(gè)位置)舍肠,然后設(shè)置一個(gè)遍歷指針current搀继,從頭開始進(jìn)行遍歷窘面。

(1)若遍歷到的位置為1翠语,則說明它一定屬于中部,根據(jù)總思路财边,中部的我們都不動(dòng)肌括,然后current向前移動(dòng)一個(gè)位置。

(2)若遍歷到的位置為0酣难,則說明它一定屬于前部谍夭,于是就和begin位置進(jìn)行交換,然后current向前移動(dòng)一個(gè)位置憨募,begin也向前移動(dòng)一個(gè)位置(表示前邊的已經(jīng)都排好了)紧索。

(3)若遍歷到的位置為2,則說明它一定屬于后部菜谣,于是就和end位置進(jìn)行交換珠漂,由于交換完畢后current指向的可能是屬于前部的,若此時(shí)current前進(jìn)則會(huì)導(dǎo)致該位置不能被交換到前部尾膊,所以此時(shí)current不前進(jìn)媳危。而同1),end向前移動(dòng)一個(gè)位置冈敛。

void quick(int a[], int first, int end)

{

int current=first;

int temp;

while (current <= end)

{

if (a[current] == 1)

{

current++;

}

else if (a[current] == 0)

{

temp = a[first];

a[first] = a[current];

a[current] = temp;

first++;

current++;

}

else if (a[current] == 2)

{

temp = a[end];

a[end] = a[current];

a[current] = temp;

end--;

}

}

}

三路快速排序

算法原理:使用三路劃分策略對(duì)數(shù)組進(jìn)行劃分(也就是荷蘭國旗問題待笑,dutch national flag problem)。這個(gè)實(shí)現(xiàn)是對(duì)實(shí)現(xiàn)二的改進(jìn)抓谴,它添加處理等于劃分元素的值的邏輯峦耘,將所有等于劃分元素的值集中在一起,并且以后都不會(huì)再對(duì)他們進(jìn)行劃分所刀。本算法中使用四個(gè)標(biāo)示值進(jìn)行操作憔四。使用left和right同時(shí)向中間遍歷時(shí),當(dāng)left遇見等于劃分元素時(shí)措拇,就與iflag指向的值進(jìn)行交換(iflag指向的當(dāng)前值到最左端表示left在過程中遇見的等于劃分元素的值部分)我纪,同理,右邊也使用同樣的邏輯完成對(duì)等于劃分元素的處理。最后分別交換左右部分的相等值(left和iflag對(duì)應(yīng)交換浅悉,right和rflag對(duì)應(yīng)交換)趟据,由于需要返回兩個(gè)標(biāo)記值,所以將partition和quicksort合并成一個(gè)方法术健。

? 算法代碼:

void quickSort_3(int *array, int l, int r) {

/**

* 由于三路劃分中有可能有兩個(gè)不同的劃分點(diǎn)汹碱,所以不能

* 使用函數(shù)直接返回,這里將partition和quickSort驅(qū)動(dòng)

* 程序結(jié)合成一個(gè)方法荞估;

* */

if(l>=r) return;

/**

* 選擇pivot劃分元素咳促,并將其與array[r]交換

* */

int pivot, temp;

pivot=l+rand()%(r-l+1);

temp=array[pivot];

array[pivot]=array[r];

array[r]=temp;

/**

* 雙向掃描:

* left和right都為主動(dòng)移動(dòng)

* lflag和rflag為被動(dòng)移動(dòng)

* */

int left=l, lflag=l;

int right=r-1, rflag=r-1;

while(true) {

while(array[left]<=array[r] && left

/**

* 如果array[left]與pivot相等,則將其交換到

* lflag當(dāng)前指向的元素

* */

if(array[left]==array[r]) {

temp=array[left];

array[left]=array[lflag];

array[lflag]=temp;

lflag++;

}

left++;

}

while(array[right]>=array[r] && right>=l) {

/**

* 如果array[right]與pivot相等勘伺,則將其交換到

* rflag當(dāng)前指向的元素

* */

if(array[right]==array[r]) {

temp=array[right];

array[right]=array[rflag];

array[rflag]=temp;

rflag--;

}

right--;

}

if(left>=right) break;

/**

* 將左邊大于pivot的元素與右邊小于pivot的元素進(jìn)行

* 交換

* */

temp=array[left];

array[left]=array[right];

array[right]=temp;

left++;right--;

}

/**

* 由于left和lflag指向的當(dāng)前元素都是即將需要處理的元素跪腹,

* 也就是當(dāng)處理結(jié)束之后,他們都需要左移一步才是已經(jīng)處理好的

* 元素飞醉; 將等于pivot的元素交換到中間

* */

lflag--;left--;

while(lflag>=l) {

temp=array[left];

array[left]=array[lflag];

array[lflag]=temp;

left--;lflag--;

}

/**

* 由于right和rflag指向的當(dāng)前元素都是即將需要處理的元素冲茸,

* 也就是當(dāng)處理結(jié)束之后,他們都需要右移一步才是已經(jīng)處理好的

* 元素缅帘;將等于pivot的元素交換到中間

* 注意:由于pivot本身也需要移動(dòng)到中間轴术,所以這里的判斷條件

* 包含r

* */

rflag++;right++;

while(rflag<=r) {

temp=array[right];

array[right]=array[rflag];

array[rflag]=temp;

right++;rflag++;

}

/**

* 最終遞歸處理左右子序列部分

* */

quickSort_3(array, l, left);

quickSort_3(array, right, r);

}

int main() {

int array[]={2,5,8,2,1,6};

quickSort_3(array,0,5);

for(int i=0;i<6;i++)

printf("%d,",array[i]);

return 1;

}

存在問題:為什么要移動(dòng)相等的值,代碼未手動(dòng)實(shí)現(xiàn)

四钦无、優(yōu)化

使用插入排序

在子序列比較小的時(shí)候逗栽,其實(shí)插排是比較快的,因?yàn)閷?duì)于有序的序列失暂,插排可以達(dá)到O(n)的復(fù)雜度彼宠,如果序列比較小,則和大序列比起來會(huì)更加有序趣席,這時(shí)候使用插排效率要比快排高兵志。其實(shí)現(xiàn)方法也很簡(jiǎn)單:快排是在子序列元素個(gè)數(shù)變成1是,才停止遞歸宣肚,我們可以設(shè)置一個(gè)閾值n想罕,假設(shè)為5,則大于5個(gè)元素霉涨,子序列繼續(xù)遞歸按价,否則選用插排。(其實(shí)在C++的STL中笙瑟,歸并算法就是采用了這個(gè)思路楼镐,當(dāng)子序列小到一定程度的時(shí)候,直接選用插排對(duì)子序列進(jìn)行排序)

快排是在待排數(shù)列越趨近于有序時(shí)變得越慢往枷,復(fù)雜度越高框产,調(diào)用插排可以很好的解決這個(gè)問題凄杯。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市秉宿,隨后出現(xiàn)的幾起案子戒突,更是在濱河造成了極大的恐慌,老刑警劉巖描睦,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件膊存,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡忱叭,警方通過查閱死者的電腦和手機(jī)隔崎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來韵丑,“玉大人爵卒,你說我怎么就攤上這事」∠ⅲ” “怎么了技潘?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵遥巴,是天一觀的道長(zhǎng)千康。 經(jīng)常有香客問我,道長(zhǎng)铲掐,這世上最難降的妖魔是什么拾弃? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮摆霉,結(jié)果婚禮上豪椿,老公的妹妹穿的比我還像新娘。我一直安慰自己携栋,他們只是感情好搭盾,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著婉支,像睡著了一般鸯隅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上向挖,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天蝌以,我揣著相機(jī)與錄音,去河邊找鬼何之。 笑死跟畅,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的溶推。 我是一名探鬼主播徊件,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼奸攻,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了虱痕?” 一聲冷哼從身側(cè)響起舞箍,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎皆疹,沒想到半個(gè)月后疏橄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡略就,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年捎迫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片表牢。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡窄绒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出崔兴,到底是詐尸還是另有隱情彰导,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布敲茄,位于F島的核電站位谋,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏堰燎。R本人自食惡果不足惜掏父,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望秆剪。 院中可真熱鬧赊淑,春花似錦、人聲如沸仅讽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽洁灵。三九已至饱岸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間处渣,已是汗流浹背伶贰。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留罐栈,地道東北人黍衙。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像荠诬,于是被迫代替她去往敵國和親琅翻。 傳聞我的和親對(duì)象是個(gè)殘疾皇子位仁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容

  • quicksort可以說是應(yīng)用最廣泛的排序算法之一,它的基本思想是分治法方椎,選擇一個(gè)pivot(中軸點(diǎn))聂抢,將小于pi...
    黎景陽閱讀 441評(píng)論 0 1
  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問題, 分享了一些自己做題目的經(jīng)驗(yàn)。 張土汪:刷leetcod...
    土汪閱讀 12,724評(píng)論 0 33
  • 快速排序通常是用于排序的最佳實(shí)用選擇棠众,雖然最壞情況下時(shí)間性能為O(n*n)琳疏,但其平均時(shí)間性能為O(nlgn)且記號(hào)...
    wsdadan閱讀 371評(píng)論 0 0
  • 快速排序(Quicksort)是對(duì)冒泡排序的一種改進(jìn)。它的基本思想是:通過一趟排序?qū)⒁判虻臄?shù)據(jù)分割成獨(dú)立的兩部分...
    笑啥風(fēng)云閱讀 880評(píng)論 0 0
  • 春天來了闸拿,花草綻放空盼,可是憂的是又到?jīng)]衣服穿的季節(jié)了,女人的衣櫥里總?cè)蹦敲匆患?dāng)季的衣服新荤。 周一揽趾,應(yīng)該人少,順便溜去...
    易水寒一x閱讀 173評(píng)論 0 0