JS中的一些排序算法

61 阅读2分钟

1.冒泡排序

实现思路:将数组中n个元素经过n-1轮的比较,每一轮的比较要在未排序部分中找出最大的数移动到数组末尾(这里的末尾并非是数组最后一个元素),同时每当比较完一轮,下一轮比较区间应该缩小

Array.prototype.bubbleSort = function () {
  for (let i = 0; i < this.length - 1; i++) {
    for (let j = 0; j < this.length - 1 - i; j++) {
      // 前者大于后者则进行交换
      if (this[j] > this[j + 1]) {
        let temp = this[j]
        this[j] = this[j + 1]
        this[j + 1] = temp
      }
    }
  }
  return this
}

image.png

2.选择排序

实现思路:将数组中n个元素经过n-1轮比较,第i轮比较会在未排序的元素中找到最小值并记录其索引,与数组索引为i的元素进行交换,经过n-1轮循环即可实现排序。

Array.prototype.selectionSort = function () {
  for (let i = 0; i < this.length; i++) {
    let index = i
    for (let j = i + 1; j < this.length; j++) {
      // 找到最小值对应的索引
      if (this[index] > this[j]) {
        index = j
      }
    }
    let temp = this[i]
    this[i] = this[index]
    this[index] = temp
  }
  return this
}

image.png

3.插入排序

实现思路:从数组索引为1开始遍历,从该位置往前比较,找到比该元素大的元素时则交换位置,下一轮循环就从索引为2开始,重复以上过程。将开始遍历的位置记作为j,还需要注意[1,j-1]之间元素,若有错位也需要交换位置。设数组有n个元素,那么经过n轮循环即可实现排序。

Array.prototype.insertSort = function () {
  for (let i = 1; i < this.length; i++) {
    let j = i
    let temp = this[i]
    while (j > 0) {
      if (temp < this[j - 1]) {
        this[j] = this[j - 1]
      } else {
        break
      }
      j--
    }
    this[j] = temp
  }
  return this
}

image.png

4.归并排序

实现思路:将整个数组分成两半,再把子数组分成两半,直至数组分成只包含单个数才结束,然后开始有序地合并元素。

Array.prototype.mergerSort = function () {
  const help = (arr) => {
    // 数组元素个数为1时 不需要再切割 直接返回
    if (arr.length === 1) return arr
    const mid = Math.floor(arr.length / 2)
    const left = arr.slice(0, mid)
    const right = arr.slice(mid, arr.length)
    const leftRes = help(left)
    const rightRes = help(right)
    const res = []

    while (leftRes.length || rightRes.length) {
      if (leftRes.length && rightRes.length) {
        // 左右数组均不为空 小的先被push
        res.push(leftRes[0] < rightRes[0] ? leftRes.shift() : rightRes.shift())
      } else if (leftRes.length) {
        // 左边数组不为空 右边数组为空
        res.push(leftRes.shift())
      } else if (rightRes) {
        // 右边数组不为空 左边数组为空
        res.push(rightRes.shift())
      }
    }
    return res
  }

  const res = help(this)
  return res
}

步骤解析:这里画图不知道怎么好表达,所以就用文字来描述一下过程。

  1. 执行help(this),left=[3,2], right=[4,1],然后执行help(left)即help([3,2])。
  2. 执行help([3,2])时,left=[3], right=[2],然后执行help(left)即help([3])。
  3. 执行help([3])时,经过判断执行return操作,所以对于执行help([3,2])这一次操作来说,其leftRes=[3]。
  4. 对于执行help([3,2])这一步,const leftRes = help([3])已执行完,此时应该开始执行help(right)即help([2])。
  5. 执行help([2])时,经过判断执行return操作,所以对于help([3,2])这一次操作来说,其rightRes=[2]。
  6. 此时对于help([3,2])来说,还剩余while循环及其后面的代码还没执行,所以此时开始执行while循环合并leftRes、rightRes到变量res中,最终res = [2, 3]。这里的res被return,所以对于help(this)这一步操作,其leftRes=res=[2,3]。
  7. 对于help(this)来说,其leftRes已经拿到了,准备开始执行const rightRes = help([4,1]),剩余过程其实上面一样,这里就不再叙述了...

总结:leftRes拿到就是左数组经过排序的数组,rightRes拿到的就是右数组经过排序的数组,再通过while循环从小到大依次合并即可。

5.快速排序

实现思路:在数组中选择一个元素作为基准,小于该基准值的元素和大于该基准值的元素分别放到两个数组里,再对子数组进行递归操作,直到子数组所有元素都是有序的。

Array.prototype.quickSort = function () {
  const help = (arr) => {
    if (arr.length <= 1) {
      return arr
    }

    const left = []
    const right = []
    const base = arr[0]
    for (let i = 1; i < arr.length; i++) {
      if (arr[i] < base) {
        left.push(arr[i])
      } else {
        right.push(arr[i])
      }
    }
    return [...help(left), base, ...help(right)]
  }

  return help(this)
}

image.png

最后

如果大家看到哪里有错误希望指出,感谢各位大佬指教!(抱拳)