淺解前端必須掌握的演算法(三):直接插入排序

程式猿何大叔發表於2018-06-26

前言

雖然前端面試中很少會考到演算法類的題目,但是你去大廠面試的時候就知道了,對基本演算法的掌握對於從事電腦科學技術的我們來說,還是必不可少的,每天花上 10 分鐘,瞭解一下基本演算法概念以及前端的實現方式。

另外,掌握了一些基本的演算法實現,對於我們日常開發來說,也是如虎添翼,能讓我們的 js 業務邏輯更趨高效和流暢。

演算法介紹

我們都應該玩過撲克牌了,遊戲期間玩家們基本上都是一邊摸牌一邊理牌,會把牌面值小的牌放到左邊,牌面值大的牌放到右邊,以升序進行排序(當然也有喜歡降序排序的玩家)。而理牌期間,我們習慣從左往右看牌面值大小,兩兩比較,將牌抽出,插入到合理的位置。這裡我們理牌的方法,就是「直接插入排序法」。

直接插入排序法的基本操作是將一個元素插入到已經排好序的陣列中,從而得到一個新的、Unicode 值遞增的陣列。

演算法圖示:

直接插入排序演算法圖示

具體實現指導:
假設陣列 arr 中共有 n 個元素,因為比較的話,起碼要兩個元素,則將要進行 n-1 輪迴圈。每一輪迴圈比較下標為 i-1、i(1 <= i <= arr.length-1) 的元素,如果後者元素 Unicode 值更大,則將後者元素先儲存到一個變數中,並稱該變數為「哨兵變數」。然後進入子迴圈。從下標為 i-1 的元素開始,每一輪子迴圈中,都去比較當前元素與「哨兵變數」的 Unicode 值,若當前元素更大,則直接將當前元素的值賦給後一個元素(下標加 1 的元素),然後繼續下一輪子迴圈,直到當前元素不大於「哨兵變數」,則退出子迴圈,繼而進行下一輪的迴圈。

具體實現

var insertSort = function(arr){
  var i, j, m, mCnt=0;
  var len = arr.length;

  for (i=1; i<len; i++) {
    if (arr[i] < arr[i-1]) {
      // 將更小的那個元素儲存起來
      m = arr[i];
      for (j=i-1; arr[j]>m; j--) {
        // 往後挪
        arr[j+1] = arr[j];
        mCnt++;
      }
      console.log('移動了 '+mCnt+' 次');
      mCnt = 0;
      // 直接插入
      arr[j+1] = m;
    }
  }

  return arr;
};

insertSort([5,4,3,2,1]);
insertSort([3, 2, 1, 7, 8, 9, 0]);
複製程式碼

複雜度分析

當最好的情況,也就是傳入的陣列本來就是有序的,比如 [1, 2, 3, 4, 5],那麼比較次數為 5-1=4 次,由於已經是有序的了,因此沒有移動的次數,時間複雜度為 O(n)

當最壞的情況,也就是傳入的陣列完全是逆序的,比如 [5, 4, 3, 2, 1],那麼需要比較如下次:

淺解前端必須掌握的演算法(三):直接插入排序

而移動的次數也將達到如下次數:

淺解前端必須掌握的演算法(三):直接插入排序

綜上所述,時間複雜度依舊為 O(n²)

相關文章