"Front-end algorithm series" How to make front-end code 60 times faster

Today's problems start from the sorting algorithm, to explain how the business needs, combined with Golden algorithms to achieve high-performance development js.

scene

The boss asked Xiao Ming to the company's 20,000 + row a sequence of data, but because of the sort of action will occur frequently, if the time to perform the operation is very slow, it will seriously degrade the user experience, after hearing this sad news Xiao Ming started code.

Sorting algorithms 1. There is no sense of violation and Xiao Ming on demand, he thought for a while, wrote the following algorithm:

/**
 * max排序
 * @param {*} arr 
 * 耗时:760ms
 */
 function maxSort(arr) {
     let result = [...arr];
     for(let i=0,len=result.length; i< len; i++) {
        let minV = Math.min(...result.slice(i))
        let pos = result.indexOf(minV,i)
        result.splice(pos, 1)
        result.unshift(minV)
     }
     return result.reverse()
 }
复制代码

Confident Xiao Ming revel in their algorithm, ready to test performance,

/*
 * @Author: Mr Jiang.Xu 
 * @Date: 2019-06-11 10:25:23 
 * @Last Modified by: Mr Jiang.Xu
 * @Last Modified time: 2019-06-13 21:03:59
 * @desc 测试函数执行的时间
 */

const testArr = require('./testArr');
module.exports = async function getFnRunTime(fn) {
    let len = testArr.length;
    let startTime = Date.now(), endTime;
    let result = await fn(testArr);
    endTime = Date.now();
    console.log(result);
    console.log(`total time:${endTime-startTime}ms`,
                'test array\'length:' + len, 
                result.length
    );
}
复制代码

After running the test function, time-consuming 760ms, Xiao Ming feel pretty good, after into the project, for the first time Fortunately operation, continuous operation several times, obviously Caton page. . . (In this case the shaded area required Xiaoming heart)

2. Bubble Sort

Xiao Ming reconciled, after the Internet to find relevant information, wrote the following bubble sort of code:

/**
  * 置换函数
  * @param {源数组} arr 
  * @param {原数组的A项} indexA 
  * @param {原数组的B项} indexB 
  */
 function swap(arr, indexA, indexB) {
    [arr[indexA], arr[indexB]] = [arr[indexB], arr[indexA]];
 }

/**
 * 原始冒泡排序
 * @param {数组} arr 
 * 耗时:377ms
 */
 function bubbleSort1(arr) {
    for (let i = arr.length - 1; i > 0; i--) {
      for (let j = 0; j < i; j++) {
        if (arr[j] > arr[j + 1]) {
          swap(arr, j, j + 1);
        }
      }
    }
  
    return arr;
  }
复制代码

After the test takes 377ms, perfect, Xiao Ming into the project test, or there will be frequent ordering cards Dayton, can no longer optimize about it? After thinking for a long time, Xiao Ming improved bubble sort:

/**
 * 利用索引优化后的冒泡排序
 * @param {数组} arr 
 * 耗时:350ms
 */ 
function bubbleSort2(arr) {
    let i = arr.length - 1;

    while (i > 0) {
        let pos = 0;

        for (let j = 0; j < i; j++) {
        if (arr[j] > arr[j + 1]) {
            pos = j;
            swap(arr, j, j + 1);
        }
        }
        i = pos;
    }

    return arr;
}
复制代码

The cache index sorted to improve performance of the position, the time savings 20ms, but the benefits are minimal. Xiao Ming began to contradict themselves, and continue to look on Wikipedia, and finally found a way:

/**
 * 在每趟排序中进行正向和反向两遍冒泡 ,
 * 一次可以得到两个最终值(最大和最小), 
 * 从而使外排序趟数大概减少了一半
 * @param {*} arr 
 * 耗时:312ms
 */
function bubbleSort3(arr) {
    let start = 0;
    let end = arr.length - 1;
  
    while (start < end) {
      let endPos = 0;
      let startPos = 0;
      for (let i = start; i < end; i++) {
        if (arr[i] > arr[i + 1]) {
            endPos = i;
            swap(arr, i, i + 1);
        }
      }
      end = endPos;
      for (let i = end; i > start; i--) {
        if (arr[i - 1] > arr[i]) {
          startPos = i;  
          swap(arr, i - 1, i);
        }
      }
      start = startPos;
    }
  
    return arr;
  }
复制代码

By bubbling in forward and reverse twice per trip ordering, Xiao Ming to reduce the time and 38ms, good ~

I recommend something more than the Wikipedia again, there is always a right for you. #### 3 after insertion sort of small-scale income victory, Xiao Ming inflated, reducing the time to sort should raving about 100ms, Amway So then the following algorithm:

/**
   * 插入排序 -- 基础版
   * @param {*} arr 
   * 耗时:897ms
   */
  function insertionSort(arr) {
    for (let i = 1, len = arr.length; i < len; i++) {
      const temp = arr[i];
      let preIndex = i - 1;
  
      while (arr[preIndex] > temp) {
        arr[preIndex + 1] = arr[preIndex];
        preIndex -= 1;
      }
      arr[preIndex + 1] = temp;
    }
  
    return arr;
  }
复制代码

897ms, Xiao Ming left no technical tears.

Xiao Ming finally come up with this special skill, he found the binary search code into the next after the last reform:

/**
   * 改造二分查找,查找小于value且离value最近的值的索引
   * @param {*} arr 
   * @param {*} maxIndex 
   * @param {*} value 
   */
  function binarySearch1(arr, maxIndex, value) {
    let min = 0;
    let max = maxIndex;
    
    while (min <= max) {
      const m = Math.floor((min + max) / 2);
  
      if (arr[m] <= value) {
        min = m + 1;
      } else {
        max = m - 1;
      }
    }
  
    return min;
  }

/**
 * 使用二分法来优化插入排序
 * @param {*} arr 
 * 耗时:86ms
 */
function insertionSort1(arr) {
    for (let i = 1, len = arr.length; i < len; i++) {
        const temp = arr[i];
        const insertIndex = binarySearch1(arr, i - 1, arr[i]);

        for (let preIndex = i - 1; preIndex >= insertIndex; preIndex--) {
        arr[preIndex + 1] = arr[preIndex];
        }
        arr[insertIndex] = temp;
    }

    return arr;
}
复制代码

Perfect, only a 86ms! Xiao Ming excitement stood up, also took under the table, completely ignoring the viewers' eyes.

Xiao Ming has not fulfilled unnecessary, and for 86ms quite satisfactory, the boss wanted to see him one unique.

4. Shell sort

Is there no room for promotion yet? Been to survey research shows that there is a better solution:

/**
 * 希尔排序
 * 核心:通过动态定义的 gap 来排序,先排序距离较远的元素,再逐渐递进
 * @param {*} arr 
 * 耗时:15ms
 */
function shellSort(arr) {
    const len = arr.length;
    let gap = Math.floor(len / 2);
  
    while (gap > 0) {
      // gap距离
      for (let i = gap; i < len; i++) {
        const temp = arr[i];
        let preIndex = i - gap;
  
        while (arr[preIndex] > temp) {
          arr[preIndex + gap] = arr[preIndex];
          preIndex -= gap;
        }
        arr[preIndex + gap] = temp;
      }
      gap = Math.floor(gap / 2);
    }
  
    return arr;
  }
复制代码

It takes 15ms, worship. #### 5. Mergesort

/**
 * 归并排序
 * @param {*} arr 
 * 耗时 30ms
 */
function concatSort(arr) {
  const len = arr.length;

  if (len < 2) { return arr; }

  const mid = Math.floor(len / 2);
  const left = arr.slice(0, mid);
  const right = arr.slice(mid);

  return concat(concatSort(left), concatSort(right));
}

function concat(left, right) {
  const result = [];

  while (left.length > 0 && right.length > 0) {
    result.push(left[0] <= right[0] ? left.shift() : right.shift());
  }

  return result.concat(left, right);
}
复制代码

Takes 30ms, also want to be good. There is no faster way to do that? The answer is yes, but involve relatively monks of mathematical knowledge, give up, boy. . .

Next will introduce more outstanding algorithm, so stay tuned Oh ~ Finally, welcome to join the group of front-end technology, to explore the charm of the front end

###more recommendations

Reproduced in: https: //juejin.im/post/5d034e83e51d45773e418a69

Guess you like

Origin blog.csdn.net/weixin_34223655/article/details/93176945