常用排序算法

76 阅读1分钟

排序算法

时间复杂度是稳定排序是原地排序
冒泡排序O(n²)
插入排序O(n²)
选择排序O(n²)
快速排序O(nlogn)
归并排序O(nlogn)
计数排序O(n+k)k是数据范围
桶排序O(n)
基数排序O(dn)d是维度

较为通用的排序算法

快速排序

export class QuickSort {
  static sort(array: number[]): void {
    this.sortInternally(array, 0, array.length - 1)
  }
  private static sortInternally(array: number[], p: number, r: number) {
    if (p >= r) return
    // 获取分界点
    const q: number = this.partition(array, p, r)
    this.sortInternally(array, p, q - 1)
    this.sortInternally(array, q + 1, r)
  }
  private static partition(array: number[], p: number, r: number): number {
    /**
     * 参考值pivot,小于pivot的放在左边,大于pivot的在右边,最后再把分界点的值和它做交换
     * 这样返回的index一定是值在中间的下标
     */
    const pivot = array[p]
    // 分界点
    let index = p + 1
    for (let i = index; i <= r; i++) {
      if (array[i] < pivot) {
        this.swap(array, index, i)
        // 找到了比标记值小的元素就移动分界点
        index++
      }
    }
    this.swap(array, p, index - 1)
    return index - 1
  }

  private static swap(array: number[], p: number, q: number) {
    const temp = array[p]
    array[p] = array[q]
    array[q] = temp
  }
}

优点时间复杂度为O(nlogn),并且是原地排序,内存占用少。可以使用三数取中法或随机数法决定中间点来平衡最差情况的出现

插入排序

sort(array: number[]) {
  for (let i = 1; i < array.length; i++) {
    let j = i - 1
    const temp = array[i]
    for (; j >= 0; j--) {
      if (array[j] > array[j + 1]) {
        array[j + 1] = array[j]
      } else {
        // 这个说明之前的已经排好了,没必要继续比较
        break
      }
    }
    array[j + 1] = temp
  }
}

优点稳定排序与原地排序,虽然时间复杂度为O(n²),但是当数据量较小时并不比O(nlogn)慢