js排序常见算法

165 阅读2分钟

记录下常见的算法,方便自己学习和理解。

排序算法

  • 冒泡排序 排序思想:判断两个相邻元素,大于则交换位置
    复杂度:O(n^2)
// [2 4 5 3 1] > [2 4 3 1 5] > [2 3 1 4 5] > 2 1 3 4 5] > [1 2 3 4 5]
function bubbleSort(arr) {
    let len = arr.length -1
    for (let i=0;i<len;i++){
        for (let j=0;j<len-i;j++){
            if (arr[j]> arr[j+1]) {
                let temp = arr[j]
                arr[j] = arr[j+1]
                arr[j+1] = temp
            }
        }
    }
    return arr
}
  • 选择排序 排序思想:每次判断,拿到最小值,交换位置
    复杂度:O(n^2)
// [2 4 5 3 1] > [1 3 5 3 2] > [1 2 5 3 4] > [1 2 3 5 4] > [1 2 3 4 5]
function selectSort(arr) {
    let len = arr.length -1
    let minIndex, temp
    for (let i=0;i<len;i++){
        minIndex = i
        for (let j=i+1;j<len;j++) {
            if (arr[minIndex] > arr[j]) {
                minIndex = j
            }
        }
        temp = arr[minIndex]
        arr[minIndex] = arr[i]
        arr[i] = temp
    }
}
  • 插入排序 排序思想:将数组分为两个,一个是已排序好的,一个是待排序的,将待排序的元素和已排序好的元素进行比较,插入适当位置。
    复杂度:O(n^2) 例子:
// [2] [4 5 3 1] > [2 4] [5 3 1] > [2 4 5] [3 1] > [2 3 4 5] [1] > [1 2 3 4 5]
function insertionSort(arr) {
    let len = arr.length
    ler prev, cur
    
    for (let i=1;i<len;i++){
        prev = i-1
        cur = arr[i]
        while(prev >= 0 && arr[prev]>cur){
            arr[prev+1] = arr[prev]
            prev--
        }
        arr[prev+1] = cur
    }
    return arr
}
  • 希尔排序 排序思想:将数组拆分成不同的间隔,对每个间隔进行插入排序,最后将全部进行一个插入排序
    复杂度:O(n^1.5)
function sort(arr) {
    let len = arr.length
    len h = Math.floor(len / 2)

    while(h >= 1) {
        for (let i=h;i<len;i++) {
            for (let j=i; j>=h && arr[j]<arr[j-h]; j-=h){
                let t = arr[j]
                arr[j] = arr[j-h]
                arr[j-h] = t
            }
        }
        h=Math.round(h/3)
    }
    return arr
}
  • 归并排序 排序思想:将数组拆分为最小单位,进行比较插入
    复杂度:O(nlogn)
// [ 2 4 5 3 1] > [2] [4] [5] [3] [1] > [2 4] [5] [3] [1] > [2 4 5] [3] [1] > [2 3 4 5] [1] > [1 2 3 4 5]。从左往右比较合并
function mregeSort(arr) {
    if (arr.length < 2) { 
        return arr; 
    } 
    let middle = Math.floor(arr.length/2); 
    let left = arr.slice(0, middle); 
    let right = arr.slice(middle); 
    return merge(mergeSort(left), mergeSort(right));
}
function merge(left, right) {
    let 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;
}
  • 快速排序 排序思想:取一个基准值,比基准值小的在左边,大的在右边,左右在继续这样的操作,最后合并 复杂度:O(nlogn)
// [ 2 4 3 5 1 ] > [ 2 1]+[ 3 ]+[ 4 5 ] > [ 1 ]+[ 2 ]+[ 3 ]+[ 4 ]+[ 5 ]
function quickSort (arr) {
    if (arr.length < 2) { // 数组元素只有一个的时候
        return arr;
    }
    let pivotIndex = Math.floor(arr.length/2);
    let pivot = arr.splice(pivotIndex,1)[0]; // 基准值
    let left = [], // 存放比基准值小的
        right = []; // 存放比基准值大的
    arr.forEach(item=>{
        if (item <= pivot) {
            left.push(item);
        } else {
            right.push(item);
        }
    })
    return quickSort(left).concat([pivot], quickSort(right));
}
  • 计数排序 排序思想:将数组的值当另一个数组的索引,再取出来,典型的空间换时间
    复杂度:O(n+m),m为元素最大值
function countingSort(arr) {
    let bucket = [],
        sortedIndex = 0;
        arrLen = arr.length;

    for (let i = 0; i < arrLen; i++) { // 拿到数组的值当索引
        if (!bucket[arr[i]]) {
            bucket[arr[i]] = 0;
        }
        bucket[arr[i]]++;
    }

    for (let i = 0,len=bucket.length; i < len; i++) {
        while(bucket[i] > 0) { // 拿到索引填充到数组中
            arr[sortedIndex] = i;
            sortedIndex++;
            bucket[i]--;
        }
    }

    return arr;
}
  • 二分法排序 排序思想:插入元素时进行排序,因为之前的元素是有序的,索引可以使用二分法,到最后小于中间值的插入中间值前面,大于或等于中间值的插入后面
    复杂度:O(nlog2^n)
function binarySort(arr, val) {
  let begin = 0;
  let end = arr.length - 1;
  let middle = Math.floor(end / 2);
  while (begin < end && arr[middle] != val) {
    // 二分排序法
    if (arr[middle] > val) {
      end = middle - 1;
    } else if (arr[middle] < val) {
      begin = middle + 1;
    }
    middle = Math.floor(begin + (end - begin) / 2);
  }
  if (arr[middle] > val) {
    // 最后找到的中间值,只有两种结果
    arr.splice(middle, 0, val);
  } else {
    arr.splice(middle + 1, 0, val);
  }
  return arr;
}