算法之三路快排

都說(shuō)快排是個(gè)很偉大的排序算法,名如其名,速度很快,而且是原位排序.

快排的精髓就在于,從數(shù)組中找一個(gè)基準(zhǔn)點(diǎn)piovt(可以隨便找,也可以找第一個(gè)),然后將數(shù)組元素移動(dòng)分區(qū),左邊小于pivot,中間部分則是等于pivot,右邊一部分是大于pivot的,然后對(duì)于左右兩部分在進(jìn)行快排.

三路快排示意圖

看上圖:

  1. 我們以首個(gè)元素為基準(zhǔn)點(diǎn),將元素分為小于 v ,等于 v , 大于 v 三個(gè)部分;而元素i則指向當(dāng)前進(jìn)行比較的元素, 區(qū)間 [l+1,lt]是小于v的元素,區(qū)間[lt+1,i-1]則表示的是等于v的元素,從最右邊的索引r處開始往內(nèi),形成的區(qū)間[gt,r]存放的是大于v的元素;

  2. 當(dāng)然一開始這些區(qū)間其實(shí)都是不存在的,我們需要確定邊界,i的開始索引指向l+1,lt的初始值是l,而gt的初始值則是r+1,表示的是這三個(gè)區(qū)間均為空;

  3. 當(dāng)排序開始時(shí)

    • 如果當(dāng)前i 指向的元素 等于v,那很好,i+1;
    • 如果當(dāng)前i 指向的元素 小于v,那么就將 lt+1 與索引 i處的值 進(jìn)行交換,
      然后lt+1, 并且 i+1;
    • 如果當(dāng)前元素 大于 v,那么 就將 gt - 1 處的元素與 當(dāng)前元素 交換,然后gt-1.
    • 最后當(dāng)i 走到 gt 處 即 gt==i 時(shí) ;那就說(shuō)明 除了第一個(gè)元素之外,其余的區(qū)間已經(jīng)分區(qū)完畢,只要將首個(gè)元素與 lt 處的元素進(jìn)行交換, 然后lt -1 ;我們就形成了想要的三個(gè)區(qū)間,小于v,等于v,然后是大于v的.

4.代碼編寫,首先是個(gè)交換函數(shù),用于交換兩個(gè)索引位置處的值

function swap(arr, a, b) {
  let temp;
  temp = arr[a];
  arr[a] = arr[b];
  arr[b] = temp;
}

5.然后就是根據(jù)上面邏輯編寫的分區(qū)函數(shù),這個(gè)函數(shù)應(yīng)當(dāng)返回,小于v,和大于v的元素的區(qū)間信息:

function partion(arr, l, r) {
  //基準(zhǔn)數(shù)選取區(qū)間的第一個(gè)值
  let v = arr[l];
  let lt = l;
  let gt = r + 1;

  for (let i = l + 1; i < gt; ) {
    if (arr[i] == v) {
      i++;
    } else if (arr[i] > v) {
      swap(arr, gt - 1, i);
      gt--;
    } else {
      swap(arr, lt + 1, i);
      lt++;
      i++;
    }
  }

  swap(arr, l, lt);
  lt--;
  return { lt: lt, gt: gt };
}

6.最后就是我們快排函數(shù) , 明顯就是用遞歸了,將沒(méi)有大于v,和小于v區(qū)間的元素在進(jìn)行快排

function quicksort(arr, l, r) {
  // 只有l(wèi)<r 才需要對(duì)元素進(jìn)行處理
  if (l >= r) {
    return;
  }
  let obj = partion(arr, l, r);
  quicksort(arr, l, obj.lt);
  quicksort(arr, obj.gt, r);
}

7.好了快排到此就實(shí)現(xiàn)了我們來(lái)編寫個(gè)測(cè)試用例 測(cè)試實(shí)現(xiàn)的這個(gè)快排 有多快

//生成一個(gè)近乎有序的數(shù)組
function randomNearlyOrderArray(count) {
  let arr = [];
  for (let i = 0; i < count; i++) {
    arr[i] = Math.floor(Math.random() * 50 + 1);
  }
  return arr;
}
//測(cè)試數(shù)組是否已經(jīng)排序
function isSorted(arr) {
  for (let i = 0; i + 2 < arr.length - 1; i++) {
    if (
      (arr[i] > arr[i + 1] && arr[i + 1] < arr[i + 2]) ||
      (arr[i] < arr[i + 1] && arr[i + 1] > arr[i + 2])
    ) {
      return false;
    }
  }
  return true;
}

8.來(lái)看看 node.js 下的實(shí)驗(yàn)結(jié)果吧,

對(duì)于生成 10000000
我們的三路快排花費(fèi)  350  ms 左右

自己寫的快排

使用Array.prototype.sort  來(lái)對(duì)數(shù)組進(jìn)行排序
則 花費(fèi)了  3500 ms 左右
Array.prototype.sort
  1. 總結(jié),看來(lái) 我們的快排在處理 近乎有序 數(shù)組時(shí) 還是 效率挺高的 ,原因就是,多了個(gè) 等于元素v的區(qū)間,這部分的元素,在形成后,下次就不需要移動(dòng)了,所以效率會(huì)很高.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市庐船,隨后出現(xiàn)的幾起案子筐钟,更是在濱河造成了極大的恐慌李破,老刑警劉巖诽俯,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件仙粱,死亡現(xiàn)場(chǎng)離奇詭異候味,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)辐真,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)昧廷,“玉大人淹办,你說(shuō)我怎么就攤上這事±驯Γ” “怎么了培己?”我有些...
    開封第一講書人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵茸炒,是天一觀的道長(zhǎng)感论。 經(jīng)常有香客問(wèn)我芳绩,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任许师,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好堡赔,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開白布悉稠。 她就那樣靜靜地躺著卦尊,像睡著了一般邓线。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上婿崭,一...
    開封第一講書人閱讀 50,084評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音徒欣,去河邊找鬼秽澳。 笑死孩锡,一個(gè)胖子當(dāng)著我的面吹牛男韧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播荆隘,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼憨颠,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了适篙?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤衩婚,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后藏研,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體业踏,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡绎巨,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年拒迅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片她倘。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡坪它,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出帝牡,到底是詐尸還是另有隱情,我是刑警寧澤蒙揣,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布靶溜,位于F島的核電站,受9級(jí)特大地震影響懒震,放射性物質(zhì)發(fā)生泄漏罩息。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一个扰、第九天 我趴在偏房一處隱蔽的房頂上張望瓷炮。 院中可真熱鬧,春花似錦递宅、人聲如沸娘香。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)烘绽。三九已至,卻和暖如春俐填,著一層夾襖步出監(jiān)牢的瞬間安接,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工英融, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留盏檐,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓驶悟,卻偏偏與公主長(zhǎng)得像胡野,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子撩银,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351

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

  • oncontextmenu="window.event.returnValue=false" 將徹底屏蔽鼠標(biāo)右鍵 ...
    逍遙至尊灬寳閱讀 1,235評(píng)論 0 43
  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問(wèn)題, 分享了一些自己做題目的經(jīng)驗(yàn)给涕。 張土汪:刷leetcod...
    土汪閱讀 12,740評(píng)論 0 33
  • 數(shù)據(jù)結(jié)構(gòu)與算法——快速排序 快速排序,顧名思義,它速度很快够庙,針對(duì)一般應(yīng)用中各種不同的輸入都要比其他排序算法快很多恭应,...
    sunhaiyu閱讀 3,260評(píng)論 0 3
  • 選擇排序 選擇排序是一種簡(jiǎn)單直觀的排序算法,無(wú)論什么數(shù)據(jù)進(jìn)去都是 O(n?) 的時(shí)間復(fù)雜度耘眨。所以用到它的時(shí)候昼榛,數(shù)據(jù)...
    無(wú)灃閱讀 1,315評(píng)論 0 0
  • 今天我很生氣、很難過(guò)剔难,誰(shuí)能告訴我胆屿,對(duì)于一個(gè)半生不熟,不懂感恩的孩子偶宫,我應(yīng)該用什么樣的態(tài)度對(duì)待她非迹? 我并不認(rèn)為,媽媽...
    午后窗臺(tái)的貓閱讀 181評(píng)論 0 0