做者:顏亦浠@毛豆前端javascript
Chrome瀏覽器和Firefox瀏覽器對一些算法的實現存在差別,之前遇到過一個問題,作了一個記錄,下面就和你們一塊兒探討下。前端
接口返回數據相同,通過排序後,同一個頁面兩個瀏覽器展現效果不一樣。java
一、前端排序算法不對git
二、其餘因素影響github
從新梳理後,發現sort用法寫的不對。算法
sort()若是不帶參數,就是按照字母順序對數組中的元素進行排序,也就是按照字母編碼的順序進行排序。chrome
若是sort()中傳入排序規則函數,則能夠自定義排序。數組
規則以下:瀏覽器
一、比較函數應該有兩個參數a,b函數
二、 若 a 小於 b,在排序後的數組中 a 應該出如今 b 以前,則返回一個小於 0 的值。若 a 等於 b,則返回 0。若 a 大於 b,則返回一個大於 0 的值。
修改以後在打斷點驗證的過程當中發現,兩個瀏覽器遍歷過程當中每一次的結果是不一樣的,雖然最終排序的結果一致。
深究發現,兩個瀏覽器內核在進行排序是所採用的算法不一樣。
火狐sort排序用的是歸併排序,chrome瀏覽器用的是插入排序、快速排序(數量小於10的數組使用 InsertionSort,比10大的數組則使用 QuickSort)
一、歸併排序(Merge Sort)
基本思想:將兩個有序數列合併成一個有序數列,包括從上往下、從下往上兩種方式,區別在於分組大小,前者傾向於首先均分爲兩個組,後者傾向於分紅每組只有一個元素的多個組。
基本demo:
// 歸併排序的通常實現
const merge = (left, right) => {
const result = [];
while (left.length && right.length) {
if(left[0] <= right[0]) {
result.push(left.shift());
} else {
result.push(right.shift())
}
}
while(left.length) result.push(left.shift());
while(right.length) result.push(right.shift());
return result;
}
const mergeSort = arr => {
const len = arr.length;
if (len < 2) {
return arr;
}
let middle = Math.floor(len/2);
let left = arr.slice(0, middle);
let right = arr.slice(middle);
return merge(mergeSort(left), mergeSort(right))
}
複製代碼
二、快速排序(Quick Sort)
基本思想:在數組中選擇一個基數,比基數大的放在右邊子數組,比基數小的放在左邊子數組,而後在分別對左右兩邊的數組分別執行以上操做,直到所分紅的數組都只有一個元素。
基本demo:
//快速排序的通常實現
const quickSort1 = arr => {
if (arr.length <= 1) {
return arr;
}
const midIndex = Math.floor(arr.length / 2);
const valArr = arr.splice(midIndex, 1);
const midIndexVal = valArr[0];
const left = [];
const right = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i] < midIndexVal) {
left.push(arr[i]);
} else {
right.push(arr[i]);
}
}
return quickSort1(left).concat(midIndexVal, quickSort1(right));
};
複製代碼
三、插入排序(Insertion Sort)
比較適用於大部分元素已經排序好的狀況。
基本思想:把整個數組拆分紅兩個子數組,一個爲按順序排好的,一個爲沒有排序的,每次從沒有排序的數組中拆除一個數,將起放入已經排序好的數組中並排好序,直到沒有排序的數組爲空爲止。
基本demo:
//插入排序的通常實現
const insertionSort = (nums) => {
for (let i = 1; i < nums.length; ++i) {
let preIndex = i -1;
let temp = nums[i];
while (j >=0 && nums[preIndex] > temp) {
nums[preIndex+1] = nums[preIndex];
preIndex--;
}
nums[preIndex+1] = temp;
}
return nums;
}
複製代碼
時間複雜度:
穩定性:
優化方案:
const binarySearch = (arr, maxIndex, value) => {
let min = 0;
let max = maxIndex;
while (min <= max) {
const mid = Math.floor((min + max) / 2);
if (arr[mid] <= value) {
min = mid + 1;
} else {
max = mid - 1;
}
}
return min;
}
const insertionSort2 = (arr) => {
for (let i = 1, len = arr.length; i < len; i++) {
const temp = arr[i];
const insertIndex = binarySearch(arr, i - 1, arr[i]);
for (let preIndex = i - 1; preIndex >= insertIndex; preIndex--) {
arr[preIndex + 1] = arr[preIndex];
}
arr[insertIndex] = temp;
}
return arr;
}
複製代碼
const swap = (arr, i, j) => {
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
};
const partition = (arr, left, right) => {
let pivot = left, //設定基準值(pivot)
index = pivot + 1;
for (let i = index; i <= right; i++) {
if (arr[i] < arr[pivot]) {
swap(arr, i, index);
index++;
}
}
swap(arr, pivot, index - 1);
return index - 1;
};
const quickSort = (arr, left, right) => {
let len = arr.length, index;
left = typeof left != 'number' ? 0 : left;
right = typeof right != 'number' ? len-1 : right;
if (left < right ) {
index = partition(arr, left, right);
quickSort(arr, left, index - 1);
quickSort(arr, index + 1, right);
}
return arr;
}
複製代碼