Skip to content
当前页导航

数据结构和算法

常用排序

冒泡排序(Bubble Sort)

解题思路

给定一个数组,从左到右依次冒泡,把较大的数往右边挪动即可。

实现

每两个元素比较大小并进行交换,直到这一轮当中最大或最小的元素被放置在数组的尾部,然后不断地重复这个过程,直到所有元素都排好位置。其中,核心操作就是元素相互比较。

1

js
const arr = [2, 1, 7, 9, 5, 8]

function sort(arr) {
  let len = arr.length
  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
}

console.log(sort(arr))

插入排序(Insertion Sort)

解题思路

不断地将尚未排好序的数插入到已经排好序的部分。

实现

首先将数组分成左右两个部分,左边是已经排好序的部分,右边是还没有排好序的部分。

2

js
const arr = [2, 1, 7, 9, 5, 8]

function sort(arr) {
  let len = arr.length
  for (let i = 1; i < len; i++) {
    let current = arr[i] // 当前要插入的元素
    let j = i - 1 // 已排序部分的最后一个元素的索引

    // 将大于current的元素向后移动
    while (j >= 0 && arr[j] > current) {
      arr[j + 1] = arr[j]
      j--
    }

    // 插入当前元素到合适位置
    arr[j + 1] = current
  }
  return arr
}

console.log(sort(arr))

归并排序(Merge Sort)

解题思路

核心是分治,就是把一个复杂的问题分成两个或多个相同或相似的子问题,然后把子问题分成更小的子问题,直到子问题可以简单的直接求解,最原问题的解就是子问题解的合并。归并排序将分治的思想体现得淋漓尽致。

实现

一开始先把数组从中间划分成两个子数组,一直递归地把子数组划分成更小的子数组,直到子数组里面只有一个元素,才开始排序。

排序的方法就是按照大小顺序合并两个元素,接着依次按照递归的返回顺序,不断地合并排好序的子数组,直到最后把整个数组的顺序排好。

3

js
const arr = [2, 1, 7, 9, 5, 8]

function sort(arr) {
  if (arr.length <= 1) {
    return arr // 当数组长度小于等于1时,无需继续拆分
  }

  let midIndex = Math.floor(arr.length / 2) // 中间索引
  let leftArr = arr.slice(0, midIndex) // 左侧数组
  let rightArr = arr.slice(midIndex) // 右侧数组

  // 递归拆分左右两个子数组
  let sortedLeftArr = sort(leftArr)
  let sortedRightArr = sort(rightArr)

  // 合并两个有序数组
  return merge(sortedLeftArr, sortedRightArr)
}

// 合并两个有序数组
function merge(leftArr, rightArr) {
  let mergedArr = []
  let leftIndex = 0
  let rightIndex = 0

  // 比较左右两个数组的元素,并按照顺序合并到结果数组中
  while (leftIndex < leftArr.length && rightIndex < rightArr.length) {
    if (leftArr[leftIndex] <= rightArr[rightIndex]) {
      mergedArr.push(leftArr[leftIndex])
      leftIndex++
    } else {
      mergedArr.push(rightArr[rightIndex])
      rightIndex++
    }
  }

  // 将剩余未合并的元素添加到结果数组中
  while (leftIndex < leftArr.length) {
    mergedArr.push(leftArr[leftIndex])
    leftIndex++
  }

  while (rightIndex < rightArr.length) {
    mergedArr.push(rightArr[rightIndex])
    rightIndex++
  }

  return mergedArr
}

console.log(sort(arr))

快速排序(Quick Sort)

解题思路

快速排序也采用了分治的思想。把原始的数组筛选成较小和较大的两个子数组,然后递归地排序两个子数组。

举例:把班里的所有同学按照高矮顺序排成一排。

解法:老师先随机地挑选了同学 A,让所有其他同学和 A 比高矮,比 A 矮的都站在 A 的左边,比 A 高的都站在 A 的右边。接下来,老师分别从左边和右边的同学里选择了同学 B 和 C,然后不断地筛选和排列下去。

在分成较小和较大的两个子数组过程中,如何选定一个基准值(也就是同学 A、B、C 等)尤为关键。

5

js
let arr = [2, 1, 7, 9, 5, 8]

function sdort(arr) {
  if (arr.length <= 1) {
    return arr // 当数组长度小于等于1时,无需排序
  }

  let pivotIndex = Math.floor(arr.length / 2) // 基准元素索引
  let pivot = arr.splice(pivotIndex, 1)[0] // 基准元素值
  let leftArr = []
  let rightArr = []

  // 将比基准元素小的元素放入左侧数组,比基准元素大的元素放入右侧数组
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] < pivot) {
      leftArr.push(arr[i])
    } else {
      rightArr.push(arr[i])
    }
  }

  // 递归排序左右两个子数组,并合并结果
  return sdort(leftArr).concat([pivot], sdort(rightArr))
}

console.log(sdort(arr))