iOS/OC:快速排序的理解與實(shí)現(xiàn)(包含單路/雙路)

快速排序(Quicksort)作為二十世紀(jì)最偉大的算法之一碌燕。快速排序的是一個(gè)時(shí)間復(fù)雜度平均為O(nlog2n)的不穩(wěn)定算法修壕。

快速排序的思想是從數(shù)組中任意選取一個(gè)元素v遏考。然后將v放到它排序好后應(yīng)該所在的正確位置,此時(shí)青团,元素v會(huì)將數(shù)組分割成兩部分督笆,
v左邊一部分都比v要小诱贿,v右邊的都比v要大珠十,之后對(duì)分割出的兩個(gè)子數(shù)組遞歸進(jìn)行此分割操作,遞歸完成時(shí)晒杈,整個(gè)數(shù)組就排好序了壳嚎。

比如烟馅,我們?nèi)我膺x擇此數(shù)組第一個(gè)元素4。

1.png

然后將4放到他排序好后的應(yīng)該所在的位置刊驴,并使4前面的都小于四捆憎,后邊的都大于4。


2.png

之后對(duì)前后兩部分繼續(xù)進(jìn)行此操作致份,即可完成整個(gè)的排序氮块。

所以對(duì)于快速排序算法來(lái)說(shuō)诡宗,最重要的就是塔沃,如何把一個(gè)選定的元素挪到正確的位置上,并且使前后兩部分的都滿足要求螃概。這也是快速排序算法的核心名扛。

在這個(gè)過(guò)程中肮韧,我們通常都選擇第一個(gè)元素來(lái)作為我們分界的標(biāo)識(shí)。我們給它起名叫v超燃,同時(shí)用索引L記錄他的位置拘领。

3.png

之后我們?cè)趯?duì)v后面的元素一個(gè)一個(gè)的遍歷過(guò)程中约素,我們將逐漸的整理出一部分是小于v的圣猎,一部分是大于v的。兩部分的分界點(diǎn)我們用J來(lái)標(biāo)識(shí)慢显。

4.png

而當(dāng)前訪問(wèn)的元素e我們用索引i來(lái)標(biāo)識(shí)荚藻。

5.png

此時(shí)數(shù)組[L+1应狱,J]這個(gè)區(qū)間都是小于v的,[J+1落塑,i-1]這個(gè)區(qū)間都是大于v的,
之后我們看i這個(gè)位置的元素e罐韩,他怎么放到兩個(gè)區(qū)間的某一個(gè)里去散吵。
我們將e與v進(jìn)行比較蟆肆,如果比v大炎功,說(shuō)明它屬于圖中紫色的大于v的區(qū)間內(nèi),此時(shí)我們直接i自增1赁温,直接指向下一個(gè)需要與v比較的元素股囊,而e就已經(jīng)是屬于紫色的大于v的區(qū)間內(nèi)了更啄。

6.png

如果e比v小呢祭务,我們就將元素e與J索引的下一個(gè)位置也就是J+1位置的元素交換。

7.png
8.png

此時(shí)e就屬于藍(lán)色小于v的區(qū)間內(nèi)了,然后將J索引自增1偎行,指向新的邊界,i索引自增1熄云,進(jìn)行下一個(gè)元素的判斷妙真。

9.png

當(dāng)所有的元素遍歷完時(shí)珍德,大于v和小于v的兩部分就分完了锈候。

10.png

最后泵琳,我們要將元素v挪到正確的位置上,只需將索引L位置的v與索引J位置的元素進(jìn)行交換谷市。

11.png
12.png

整個(gè)操作就完成了迫悠。之后對(duì)藍(lán)色的小于v部分和紫色大于v部分的子數(shù)組重復(fù)以上操作巩梢,整個(gè)快速排序就完成了且改。


接下來(lái),我們用代碼實(shí)現(xiàn)一下快速排序碍拆。

  NSMutableArray * array = [NSMutableArray arrayWithObjects:@8,@7,@6,@5,@4,@3,@2,@1, nil];
//調(diào)用排序
[self quickSortArray:array];

- (void)quickSortArray:(NSMutableArray *)array {
  [self quickSort:array low:0 high:array.count - 1];
}
- (void)quickSort:(NSMutableArray *)array low:(int)low high:(int)high {
  //遞歸退出條件判斷
  if (low>=high) {
    return;
  }
  //對(duì)數(shù)組進(jìn)行分割操作感混,返回分界處索引index
  int index =  [self quick:array low:low high:high];

  //對(duì)從最低位索引low到分界處索引index前一位的元素遞歸進(jìn)行分割操作
  [self quickSort:array low:low high:index-1];

  //對(duì)分界處索引index的后一位到末尾索引high進(jìn)行遞歸分割操作
  [self quickSort:array low:index + 1 high:high];
}

- (int)quick:(NSMutableArray *)array low:(int)low high:(int)high {
  //分界處索引j的初始值為數(shù)組第一個(gè)元素的索引---low
  int j = low;
  //記錄第一個(gè)元素的大小礼烈,方便與之后遍歷的元素比較
  NSInteger key = [array[low] integerValue];
 
  for (int i = low + 1; i <= high; i++) {
    //如果當(dāng)前元素小于開(kāi)始選取的第一個(gè)元素此熬,則交換索引j+1和i的元素滑进,同時(shí)j自增1.
    if ([array[i] integerValue] < key) {
        [array exchangeObjectAtIndex:j+1 withObjectAtIndex:i];
        j++;
    }
  }
  //全部遍歷完成后扶关,交換索引low與j的元素数冬,將第一個(gè)元素放到正確的位置
  [array exchangeObjectAtIndex:low withObjectAtIndex:j];
  //返回分界點(diǎn)索引
  return j;
}

雙路快速排序
當(dāng)數(shù)組中很多重復(fù)的元素時(shí),上文的那種做法會(huì)將數(shù)組中與選定元素v相等的元素極不平衡的分配到前后兩個(gè)部分中,這種情況我們之前快速排序算法就會(huì)退化成趨近于O(n2)級(jí)別的算法拐纱。

13.png

解決方式就是秸架,之前我們是單一的從左側(cè)開(kāi)始遍歷元素咕宿,分出兩個(gè)部分,現(xiàn)在我們從數(shù)組左右兩側(cè)分別開(kāi)始遍歷。

我們將小于等于v和大于等于v的分別放在數(shù)組的兩端芽突,用i代表從左向右遍歷的位置寞蚌,J代表從右向左遍歷的位置挟秤。


14.png

i向后遍歷時(shí),如果當(dāng)前元素小于v則繼續(xù)向后遍歷管宵,如果大于等于v則停止箩朴。
J向前遍歷如果當(dāng)前元素大于v則繼續(xù)向前遍歷秋度,如果小于等于v則停止荚斯。

15.png

此時(shí)我們將索引i的元素e和索引J處的元素o交換下位置查牌,就好了僧免。

16.png
17.png

之后i繼續(xù)向后遍歷懂衩,J繼續(xù)向前遍歷浊洞。

18.png

直到i和J重合法希,就結(jié)束了靶瘸。
數(shù)組中即使有大量相等的元素,也會(huì)平均分到兩端屋剑。
代碼實(shí)現(xiàn)一下雙路快速排序唉匾。

 NSMutableArray * array = [NSMutableArray     arrayWithObjects:@8,@7,@6,@5,@4,@3,@2,@1, nil];
//調(diào)用排序
[self quickSortArray:array];

- (void)quickSortArray:(NSMutableArray *)array {
  [self quickSort:array low:0 high:array.count - 1];
}
- (void)quickSort:(NSMutableArray *)array low:(int)low high:    (int)high {
  if (low>=high) {
    return;
  }
 int index =  [self quick:array low:low high:high];
 [self quickSort:array low:low high:index-1];
 [self quickSort:array low:index + 1 high:high];
}

- (int)quick:(NSMutableArray *)array low:(int)low high:(int)high {
  int j = high;
  int i = low + 1;
  NSInteger key = [array[low] integerValue];
  while (true) {
    while (i <= high && [array[i] integerValue] < key) {
        i++;
    }
    while (j>=low + 1 && [array[j] integerValue] > key) {
        j--;
    }
    if(i > j) {
        break;
    }
    [array exchangeObjectAtIndex:i withObjectAtIndex:j];
    i++;
    j--;
  }
  [array exchangeObjectAtIndex:low withObjectAtIndex:j];
  return j;
}

如果覺(jué)得作者對(duì)哪里的理解有偏差或者其他的優(yōu)化巍膘,希望不吝賜教芋簿,留言指正与斤。謝謝支持~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末幽告,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子齐唆,更是在濱河造成了極大的恐慌冻河,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,640評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件堪澎,死亡現(xiàn)場(chǎng)離奇詭異樱蛤,居然都是意外死亡剑鞍,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)蚁署,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)便脊,“玉大人,你說(shuō)我怎么就攤上這事光戈∧奶担” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,011評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵久妆,是天一觀的道長(zhǎng)晌杰。 經(jīng)常有香客問(wèn)我,道長(zhǎng)镇饺,這世上最難降的妖魔是什么乎莉? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,755評(píng)論 1 294
  • 正文 為了忘掉前任奸笤,我火速辦了婚禮,結(jié)果婚禮上哼鬓,老公的妹妹穿的比我還像新娘监右。我一直安慰自己,他們只是感情好异希,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,774評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布健盒。 她就那樣靜靜地躺著,像睡著了一般称簿。 火紅的嫁衣襯著肌膚如雪扣癣。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,610評(píng)論 1 305
  • 那天憨降,我揣著相機(jī)與錄音父虑,去河邊找鬼。 笑死授药,一個(gè)胖子當(dāng)著我的面吹牛士嚎,可吹牛的內(nèi)容都是我干的呜魄。 我是一名探鬼主播,決...
    沈念sama閱讀 40,352評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼莱衩,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼爵嗅!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起笨蚁,我...
    開(kāi)封第一講書(shū)人閱讀 39,257評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤睹晒,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后括细,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體伪很,經(jīng)...
    沈念sama閱讀 45,717評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,894評(píng)論 3 336
  • 正文 我和宋清朗相戀三年勒极,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了是掰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,021評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡辱匿,死狀恐怖键痛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情匾七,我是刑警寧澤絮短,帶...
    沈念sama閱讀 35,735評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站昨忆,受9級(jí)特大地震影響丁频,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜邑贴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,354評(píng)論 3 330
  • 文/蒙蒙 一席里、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拢驾,春花似錦奖磁、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,936評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至稠腊,卻和暖如春躁染,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背架忌。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,054評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工吞彤, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鳖昌。 一個(gè)月前我還...
    沈念sama閱讀 48,224評(píng)論 3 371
  • 正文 我出身青樓备畦,卻偏偏與公主長(zhǎng)得像低飒,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子懂盐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,974評(píng)論 2 355

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

  • 最近在讀< >時(shí),了解到了很多常用的排序算法,故寫(xiě)一篇讀書(shū)筆記記錄下這些排序算法的思路和實(shí)現(xiàn). 冒泡排序 冒泡排序...
    SylvanasSun閱讀 688評(píng)論 0 0
  • quicksort可以說(shuō)是應(yīng)用最廣泛的排序算法之一褥赊,它的基本思想是分治法,選擇一個(gè)pivot(中軸點(diǎn))莉恼,將小于pi...
    黎景陽(yáng)閱讀 447評(píng)論 0 1
  • 某次二面時(shí)拌喉,面試官問(wèn)起Js排序問(wèn)題,吾絞盡腦汁回答了幾種俐银,深感算法有很大的問(wèn)題尿背,所以總計(jì)一下! 排序算法說(shuō)明 (1...
    流浪的先知閱讀 1,193評(píng)論 0 4
  • 出遠(yuǎn)門(mén)汽久,你最擔(dān)心什么。相信有很多踊餐。但是我最擔(dān)心的是話費(fèi)景醇,幾分鐘長(zhǎng)途電話,就要幾塊錢(qián)吝岭,顯然是接受不了的三痰,一點(diǎn)電話體驗(yàn)...
    3C菜鳥(niǎo)閱讀 468評(píng)論 0 0
  • 很多人,折騰了很久以后才明白窜管,才發(fā)現(xiàn)原來(lái)此路不通散劫。生活又要回到原點(diǎn),重新折騰幕帆。
    A分享閱讀 364評(píng)論 0 1