三種基礎(chǔ)的排序算法

在計算機科學所使用的排序算法通常被分類為:

  • 計算的 時間復雜度(最差、平均、和最好性能),依據(jù)列表(list)的大小(n)。一般而言,好的性能是O(n log n),且壞的性能是O(n^2)。對于一個排序理想的性能是O(n)。僅使用一個抽象關(guān)鍵比較運算的排序算法總平均上總是至少需要O(n log n)
  • 存儲器使用量(以及其他電腦資源的使用)
    穩(wěn)定性:穩(wěn)定排序算法會讓原本有相等鍵值的紀錄維持相對次序。也就是如果一個排序算法是穩(wěn)定的,當有兩個相等鍵值的紀錄R和S,且在原本的列表中R出現(xiàn)在S之前,在排序過的列表中R也將會是在S之前。
  • 依據(jù)排序的方法:插入、交換、選擇、合并等等。

依據(jù)排序的方法分類的三種排序算法:

冒泡排序

冒泡排序?qū)σ粋€需要進行排序的數(shù)組進行以下操作:

  1. 比較第一項和第二項;
  2. 如果第一項應該排在第二項之后, 那么兩者交換順序;
  3. 比較第二項和第三項;
  4. 如果第二項應該排在第三項之后, 那么兩者交換順序;
  5. 以此類推直到完成排序;

冒泡排序.gif

實例說明:

將數(shù)組[3, 2, 4, 5, 1]以從小到大的順序進行排序:

  1. 3應該在2之后, 因此交換, 得到[2, 3, 4, 5, 1];
  2. 3, 4順序不變, 4, 5也不變, 交換5, 1得到[2, 3, 4, 1, 5];
  3. 第一次遍歷結(jié)束, 數(shù)組中最后一項處于正確位置不會再有變化, 因此下一次遍歷可以排除最后一項;
  4. 開始第二次遍歷, 最后結(jié)果為[2, 3, 1, 4, 5], 排除后兩項進行下一次遍歷;
  5. 第三次遍歷結(jié)果為[2, 1, 3, 4, 5];
  6. 最后得到[1, 2, 3, 4, 5], 排序結(jié)束;

代碼實現(xiàn):

function swap(items, firstIndex, secondIndex){
      var temp = items[firstIndex];
      items[firstIndex] = items[secondIndex];
      items[secondIndex] = temp;
};
function bubbleSort(items){
      var len = items.length, i, j, stop;
      for (i = 0; i < len; i++){
        for (j = 0, stop = len-i; j < stop; j++){
          if (items[j] > items[j+1]){
            swap(items, j, j+1);
          }
        }
      }
      return items;
}

外層的循環(huán)決定需要進行多少次遍歷, 內(nèi)層的循環(huán)負責數(shù)組內(nèi)各項的比較, 還通過外層循環(huán)的次數(shù)和數(shù)組長度決定何時停止比較.

冒泡排序極其低效, 因為處理數(shù)據(jù)的步驟太多, 對于數(shù)組中的每n項, 都需要n^2次操作來實現(xiàn)該算法(實際比n^2略小, 但可以忽略, 具體原因見??), 即時間復雜度為O(n^2).

對于含有n個元素的數(shù)組, 需要進行(n-1)+(n-2)+...+1次操作, 而(n-1)+(n-2)+...+1 = n(n-1)/2 = n^2/2 - n/2, 如果n趨于無限大, 那么n/2的大小對于整個算式的結(jié)果影響可以忽略, 因此最終的時間復雜度用O(n^2)表示

選擇排序

選擇排序?qū)σ粋€需要進行排序的數(shù)組進行以下操作:

1.假定數(shù)組中的第一項為最小值(min);

  1. 比較第一項和第二項的值;
  2. 若第二項比第一項小, 則假定第二項為最小值;
  3. 以此類推直到排序完成.

選擇排序.gif

實例說明:

將數(shù)組["b", "a", "d", "c", "e"]以字母a-z的順序進行排序:

  1. 假定數(shù)組中第一項"b"(index0)為min;
  2. 比較第二項"a"與第一項"b", 因"a"應在"b"之前的順序, 故"a"(index1)為min;
  3. 然后將min與后面幾項比較, 由于"a"就是最小值, 因此min確定在index1的位置;
  4. 第一次遍歷結(jié)束后, 將假定的min(index0), 與真實的min(index1)進行比較, 真實的min應該在index0的位置, 因此將兩者交換, 第一次遍歷交換之后的結(jié)果為["a", "b", "d", "c", "e"];
  5. 然后開始第二次遍歷, 遍歷從第二項(index1的位置)開始, 這次假定第二項為最小值, 將第二項與之后幾項逐個比較, 因為"b"就在應該存在的位置, 所以不需要進行交換, 這次遍歷之后的結(jié)果為["a", "b", "d", "c", "e"];
    6.之后開始第三次遍歷, "c"應為這次遍歷的最小值, 交換index2("d"),index3("c")位置, 最后結(jié)果為["a", "b", "c", "d", "e"];
  6. 最后一次遍歷, 所有元素在應有位置, 不需要進行交換.

代碼實現(xiàn):

function swap(items, firstIndex, secondIndex){
  var temp = items[firstIndex];
  items[firstIndex] = items[secondIndex];
  items[secondIndex] = temp;
};

function selectionSort(){
  let items = [...document.querySelectorAll('.num-queue span')].map(num => +num.textContent);
  let len = items.length, min;

  for (i = 0; i < len; i++){
    min = i;
    for(j = i + 1; j < len; j++){
      if(items[j] < items[min]){
        min = j;
      }
    }
    if(i != min){
      swap(items, i, min);
    }
  }
  return items;
};

外層循環(huán)決定每次遍歷的初始位置, 從數(shù)組的第一項開始直到最后一項. 內(nèi)層循環(huán)決定哪一項元素被比較.

選擇排序的時間復雜度為O(n^2).

插入排序

與上述兩種排序算法不同, 插入排序是穩(wěn)定排序算法(stable sort algorithm), 穩(wěn)定排序算法指不改變列表中相同元素的位置, 冒泡排序和選擇排序不是穩(wěn)定排序算法, 因為排序過程中有可能會改變相同元素位置. 對簡單的值(數(shù)字或字符串)排序時, 相同元素位置改變與否影響不是很大. 而當列表中的元素是對象, 根據(jù)對象的某個屬性對列表進行排序時, 使用穩(wěn)定排序算法就很有必要了.

一旦算法包含交換(swap)這個步驟, 就不可能是穩(wěn)定的排序算法. 列表內(nèi)元素不斷交換, 無法保證先前的元素排列為止一直保持原樣. 而插入排序的實現(xiàn)過程不包含交換, 而是提取某個元素將其插入數(shù)組中正確位置.

插入排序的實現(xiàn)是將一個數(shù)組分為兩個部分, 一部分排序完成, 一部分未進行排序. 初始狀態(tài)下整個數(shù)組屬于未排序部分, 排序完成部分為空. 然后進行排序, 數(shù)組內(nèi)的第一項被加入排序完成部分, 由于只有一項, 自然屬于排序完成狀態(tài). 然后對未完成排序的余下部分的元素進行如下操作:

  1. 如果這一項的值應該在排序完成部分最后一項元素之后, 保留這一項在原有位置開始下一步;
  2. 如果這一項的值應該排在排序完成部分最后一項元素之前, 將這一項從未完成部分暫時移開, 將已完成部分的最后一項元素移后一個位置;
  3. 被暫時移開的元素與已完成部分倒數(shù)第二項元素進行比較;
  4. 如果被移除元素的值在最后一項與倒數(shù)第二項的值之間, 那么將其插入兩者之間的位置, 否則繼續(xù)與前面的元素比較, 將暫移出的元素放置已完成部分合適位置. 以此類推直到所有元素都被移至排序完成部分.

插入排序.gif

實例說明:

現(xiàn)在需要將數(shù)組var items = [5, 2, 6, 1, 3, 9];進行插入排序:

  1. 5屬于已完成部分, 余下元素為未完成部分. 接下來提取出2, 因為5比2大, 于是5被移至靠右一個位置, 覆蓋2, 占用2原本存在的位置. 這樣本來存放5的位置(已完成部分的首個位置)就被空出, 而2在比5小, 因此將2置于這個位置, 此時結(jié)果為[2, 5, 6, 1, 3, 9];
  2. 接下來提取出6, 因為6比5大, 所以不操作提取出1, 1與已完成部分各個元素(2, 5, 6)進行比較, 應該在2之前, 因此2, 5, 6各向右移一位, 1置于已完成部分首位, 此時結(jié)果為[1, 2, 5, 6, 3, 9];
  3. 對余下未完成元素進行類似操作, 最后得出結(jié)果[1, 2, 3, 5, 6, 9];

代碼實現(xiàn):

function insertionSort(items) {
  let len = items.length, value, i, j;
  for (i = 0; i < len; i++) {
    value = items[i];
    for (j = i-1; j > -1 && items[j] > value; j--) {
      items[j+1] = items[j];
    }
    items[j+1] = value;
  }
  return items;
};

外層循環(huán)的遍歷順序是從數(shù)組的第一位到最后一位, 內(nèi)層循環(huán)的遍歷則是從后往前, 內(nèi)層循環(huán)同時負責元素的移位.

插入排序的時間復雜度為O(n^2)

以上三種排序算法都十分低效, 因此實際應用中不要使用這三種算法, 遇到需要排序的問題, 應該首先使用JavaScript內(nèi)置的方法Array.prototype.sort();

參考:

2015-CS50-week-算法
排序算法-JavaScript描述
三種基礎(chǔ)的排序算法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,002評論 6 542
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,400評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,136評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,714評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,452評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,818評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,812評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,997評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,552評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,292評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,510評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,721評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,121評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,429評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,235評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,480評論 2 379

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

  • Ba la la la ~ 讀者朋友們,你們好啊,又到了冷鋒時間,話不多說,發(fā)車! 1.冒泡排序(Bub...
    王飽飽閱讀 1,809評論 0 7
  • 排序算法說明 (1)排序的定義:對一序列對象根據(jù)某個關(guān)鍵字進行排序; 輸入:n個數(shù):a1,a2,a3,…,an輸出...
    BULL_DEBUG閱讀 796評論 0 3
  • 我的生物鐘徹底紊亂了,早上沒精神,晚上精神好的很。所有需要用腦子的事情,都必須到中午11點以后才能做。而且常常要到...
    百合手工閱讀 345評論 5 0
  • 老是畫不好眼睛和手~還要好好學習
    鉛筆只演繹黑白閱讀 220評論 0 0
  • 今天出發(fā)去陜西的最北邊啦-榆林。一路北上! 今天喉嚨痛的比昨天厲害了,不知道她是不是也變得嚴重了,希望不是不是。 ...
    阿立立哥閱讀 158評論 0 0