Author: Yan Yi @ Edamame

Chrome browser and Firefox browser on some algorithm implementation differences, encountered a problem before, made a record, and we discuss the following.

I. Problem description

The interface returns the same data. After sorting, the same page is displayed differently in two browsers.

Second, problem location

1. The front-end sorting algorithm is wrong

2. Other factors

After recombing, I found that “sort” was written incorrectly.

Sort (), if it takes no arguments, sorts the elements in the array alphabetically, in alphabetical order.

If a collation function is passed in sort(), you can customize the sort.

Here are the rules:

1. The comparison function should take two arguments, a and b

2, If a is less than B, a should precede B in the sorted array, then return a value less than 0. If a is equal to b, 0 is returned. If a is greater than b, return a value greater than 0.

After the modification, in the process of breaking point verification, it was found that the results of each browser traversal were different, although the final sorting results were the same.

Further investigation revealed that the two browser kernels used different algorithms for sorting.

Firefox sort uses merge sort, Chrome uses insert sort, QuickSort (InsertionSort for arrays less than 10, QuickSort for arrays larger)

Three, the basic implementation and comparison of several algorithms

Merge Sort (Merge Sort)

Basic idea: combine two ordered sequences into an ordered sequence, including top-down and bottom-up methods. The difference lies in the grouping size. The former tends to be divided into two groups at first, while the latter tends to be divided into multiple groups with only one element in each group.

Basic demo:

   // A general implementation of merge sort
    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))
    }
Copy the code

2. Quick Sort

The basic idea is to select a cardinality in the array, place those larger than the cardinality in the right subarray, and those smaller than the cardinality in the left subarray, and then do the same for the left and right arrays until the array is divided into only one element.

Basic demo:

    // A general implementation of quicksort
    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));
};
Copy the code

1, Insertion Sort

This applies when most elements are already sorted.

Basic idea: divide the whole array into two subarrays, one is sorted, one is not sorted, remove a number from the unsorted array each time, put it into the sorted array, until the unsorted array is empty.

Basic demo:

    // A general implementation of insert sort
    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;
    }
Copy the code

Four, performance analysis

Time complexity:

  • Merge sort (O(nlogn))
  • Quick sort (O(nlogn))
  • Insertion sort (O(n²))

Stability:

  • Merge sort (stable)
  • Quicksort (unstable)
  • Insertion sort (stable)

Optimization scheme:

  • Insertion sort: Split insertion with binary lookup
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;
    }
Copy the code
  • Merge sort: space optimization, array.splice instead of array.slice, to reduce space consumption; For the smaller subarrays, insert sort is used.
  • Quicksort: in-place
 const swap = (arr, i, j) = > {
        let temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    };
    const partition = (arr, left, right) = > {
        let pivot = left, // Set the pivot value
        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 = typeofleft ! ='number' ? 0 : left;
        right = typeofright ! ='number' ? len- 1 : right;
        if (left < right ) {
            index = partition(arr, left, right);
            quickSort(arr, left, index - 1);
            quickSort(arr, index + 1, right);
        }
        return arr;
    }
Copy the code