v8--sort 方法 源碼 (1) 插入排序法

v8--sort方法源碼中對於長度較短的數組使用的是插入排序法。數組

部分源碼:app

function InsertionSort(a, from, to) {
    for (var i = from + 1; i < to; i++) {
      var element = a[i];
      // Pre-convert the element to a string for comparison if we know
      // it will happen on each compare anyway.
      var key =
          (custom_compare || %_IsSmi(element)) ? element : ToString(element);
      // place element in a[from..i[
      // binary search
      var min = from;
      var max = i;
      // The search interval is a[min..max[
      while (min < max) {
        var mid = min + ((max - min) >> 1);
        var order = Compare(a[mid], key);
        if (order == 0) {
          min = max = mid;
          break;
        }
        if (order < 0) {
          min = mid + 1;
        } else {
          max = mid;
        }
      }
      // place element at position min==max.
      for (var j = i; j > min; j--) {
        a[j] = a[j - 1];
      }
      a[min] = element;
    }
  }

源碼的理解:函數

參數:a--數組。form起點索引即0。to終點索引。spa

源碼對數組長度進行了計算,如值爲undefined會被移至數組末尾而且長度會減去。3d

一般若是是正經的數組to就是a.length。調試

須要注意的是,以上都僅僅是在初始數組長度小於22時的狀況。code

此插入排序法是將待比較的數值與外層循環當前值對比,外層循環是從第二個數值開始的。orm

開始循環數組,索引初值爲1。建立一個哨兵,保存當前循環索引對應的值 。blog

即key = a[i],該值須要插入到已循環數組的某個位置。排序

 

建立max,記錄已循環次數。即 max = i

建立min,記錄插入位置。初值是0 即 min = 0

內層循環1,目的找出插入的位置。循環條件 min < max

該循環內,建立mid 保存min和max的中值。而後計算該中值對應的數組值與哨兵的大小。即compare(arr[mid], key)

須要注意的是,mid min max 都是數組的索引。

 若是計算結果爲0,即說明索引中值對應值與哨兵值相等。

那麼插入位置就是這個點。把mid賦值給min,取得插入點。退出該循環

 若是計算值小於0。好比已經排序好的有序數組個數是15。索引中值是7。a[7]與key(即a[16])比較小於0。即key大於a[7]

說明key應該要插入到a[7]後面。則插入點最起碼應該在索引7後面。故令min = 7 + 1;而後繼續循環找出最合適的位置。

若是計算值大於0,仍是上面那個例子。a[7]與key(即a[16])比較大於0。即key小於a[7]

說明key應該要插入到a[7]前面。則插入點最起碼應該在索引7前面。故令max = mid;而後繼續循環找出最合適的位置。

 該循環一直到min = max後結束。取得min值。

接着以當前已循環次數i做爲初始值,另存副本j = i,以j > min做爲判斷條件。

依次把前一索引值賦值給當前索引值,如 a[16] = a[15],a[15] = a[14] 等等等

最後把哨兵賦值給插入點。即a[min] = key

 至於排序是爲升降序。則由比較函數的判斷 

如最簡單的比較函數:(x, y) => return x - y

返回參數1 減去 參數2 的值。即索引中值對應值減去哨兵 

索引中值對應值小於哨兵,則計算結果小於0。按照上述邏輯,把mid+1賦值給min。則插入點在該索引後面,故爲升序

索引中值對應值大於哨兵,則計算結果大於0。按照上述邏輯,把mid賦值給max。則插入點在該索引前面,仍是升序

圖解

 

 代碼:

function insertSort(arr) {

  for(let i= 1; i < arr.length; i++) {
    let key = arr[i] // 哨兵,保存當前循環索引對應的值,須要插入到已循環數組中

    let min = 0 // 插入位置
    let max = i // 已循環次數

    // 遍歷已循環的數組,找尋插入位置
    while(min < max) {
      // 中值 >>有符號右移 相似於 Math.floor(int/2) int是正整數
      let mid = min + ((max - min) >>1)         
      // 比較函數,傳入索引中值對應的值和哨兵
      const order = compare(a[mid], key)

      // 若是等於0 
      if (order === 0) {
        // 把mid賦值給min。做爲插入位置,退出循環
        min = max = mid
        break;
      }
    // 小於0。插入位置在該索引中值後面
      if (order < 0) {
        min = mid + 1
      } else { // 大於0。插入位置在該索引中值前面
        max = mid
      }
    }

    for (let j = i; j > min; j--) {
      arr[j] = arr[j - 1]
    }
  // 插入 arr[min]
= key } }

調試:

相關文章
相關標籤/搜索