排序

Mon Jun 12 2023 · 1min

基本概念

什么是稳定的排序算法?

排序完 数字的相对位置没有变, 也就是对于数组里有重复数字的 case,如果排序后相对位置没有变,那就是稳定排序

以下默认都是按照升序处理

冒泡排序

  • 两个两个比较,如果前者比后者大,则交换两个元素的位置
  • 冒泡排序最好的时间复杂度为 O(n)。冒泡排序的最坏时间复杂度为 O(n^2)。因此冒泡排序总的平均时间复杂度为 O(n^2)。
  • 算法适用于少量数据的排序,是稳定的排序方法。
function bubbleSort(arr: number[]) {
  const len = arr.length
  for (let i = 0; i < len; i++) {
    for (let j = i + 1; j < len; j++) {
      if (arr[j] < arr[i])
        [arr[i], arr[j]] = [arr[j], arr[i]]
    }

  }
  return arr
}

选择排序

  • 找到一组数据中最小(大)的那个数,然后放到最前面
  • 不稳定 O(n^2)
function selectSort(arr: number[]) {
  const len = arr.length

  for (let i = 0; i < len - 1; i++) {
    let minIndex = i
    for (let j = i + 1; j < len; j++) {
      if (arr[j] < arr[minIndex])
        minIndex = j
    }

    [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]]
  }
}

插入排序

  • 选择基准值 放置已经排序好的文件中
  • 从数组的第二项开始 往前开始插入
  • 时间复杂度 O(n^2) 适用于少量数据排序 稳定排序

代码示例:

/**
 * 插入排序
 * 将待插入值tmp放在合适位置
 * 怎么找合适的位置? 从目标值位置向前遍历,把大于tmp的移动到
 */
function insertSort(arr: number[]) {
  for (let i = 1; i < arr.length; i++) {
    const tmp = arr[i]
    let j = i
    for (; j > 0 && arr[j - 1] > tmp; j--) arr[j] = arr[j - 1] // 把比目标值的元素右移动

    arr[j] = tmp
    console.log('arr', arr)
  }
}

快速排序

  • 选择一个基准值,采用双指针(left, right)将待排数组分成两个部分
  • 小于基准值的放到左边;大于基准值的放到右边;等于的放到任意一边都可
  • 直到 left === right 即第一轮排序完成
  • 然后递归排序基准值左侧数据 和 基准值右侧数据
  • 非稳定排序 时间复杂度 O(logn)

注意这里无需进行数据交换,而是直接 O(1)来插入到指定位置

代码示例:

const arr1 = [5, 4, 7, 2, 11, 1, 13]

function quickSort(arr, _left, _right) {
  let left = _left
  let right = _right
  const pivot = arr[left]
  if (left <= right) {
    while (left !== right) {
      while (right > left && arr[right] >= pivot) right--

      arr[left] = arr[right]

      while (left < right && arr[left] <= pivot) left++
      arr[right] = arr[left]
    }
    arr[right] = pivot
    quickSort(arr, _left, left - 1)
    quickSort(arr, right + 1, _right)
  }
}

quickSort(arr1, 0, arr1.length - 1)
console.log('arr', arr1)

希尔排序

  • 先分组 按照对半砍这么区分,比如分组跨度值为 5, 那么取下标为 0 5 10…的一组
  • 每个组里按照插入排序排
  • 等跨度为 1 排完后 基本排好了
  • 不稳定 最好 O(nlogn) 最差 O(n^2)
function shellSort(arr: number[]) {
  const len = arr.length
  for (let gap = Math.floor(len / 2); gap > 0; gap = Math.floor(gap / 2)) {
    for (let i = gap; i < len; i++) {
      const tmp = arr[i]
      let j = i
      for (; j >= gap && arr[j - gap] > tmp; j -= gap) arr[j] = arr[j - gap]

      arr[j] = tmp
    }
  }
}

堆排序

  • 构建大(小)顶堆, 从第一个非叶子节点开始
  • 构建完后 将堆顶元素和末尾元素交换
  • 然后继续将剩下的 len - 1 个元素进行 堆化,这里从堆顶开始即可,因为下边子树的根节点已经是对应的最大值了,只需要从堆顶及其子元素找出最大值即可
function heapSort(arr: number[]) {
  let len = arr.length
  function heapify(arr: number[], index: number, length: number) {
    const left = 2 * index + 1
    const right = 2 * index + 2
    let largest = index
    if (left < length && arr[left] > arr[largest])
      largest = left
    if (right < length && arr[right] > arr[largest])
      largest = right
    if (largest !== index)
      [arr[largest], arr[index]] = [arr[index], arr[largest]]

  }
  for (let i = Math.floor(len / 2) - 1; i >= 0; i--)
    heapify(arr, i, len)

  for (let i = len - 1; i > 0; i--) {
    [arr[0], arr[i]] = [arr[i], arr[0]]

    len--
    heapify(arr, 0, len)
  }
}
Leave a comment
点击切换主题
... 人来过