JavaScript 中常用的排序

JavaScript 中常用的排序

start

  • 排序是日常编码中经常遇到的需求。
  • 写这篇文章的目的,就是希望自己在写完这篇文章之后,能够非常熟悉常见的排序。

1. sort

JavaScript 中数组自带 sort 方法。

注意事项:

  1. sort 方法默认排序顺序为按字母升序。

  2. 使用数字排序,你必须通过一个函数作为参数来调用。

    利用函数指定数字是按照升序还是降序排列。

使用示例

console.log([1, 2, 20, 45, 7, 3, 4].sort())
// [1, 2, 20, 3, 4, 45, 7]

console.log([1, 2, '40', '5', 7, 3, 4].sort())
//  [1, 2, 3, 4, '40', '5', 7]

console.log(
  [1, 2, '40', '5', 7, 3, 4].sort((a, b) => {
    return a - b
  })
)
//  [1, 2, 3, 4, '5', 7, '40']

冒泡排序

手写冒泡排序1

function bubbleSort(arr) {
  for (var i = 0; i < arr.length; i++) {
    for (var j = 0; j < arr.length - i - 1; j++) {
      if (arr[j] > arr[j + 1]) {
        var temp = arr[j + 1]
        arr[j + 1] = arr[j]
        arr[j] = temp
      }
    }
  }

  return arr
}

console.log(bubbleSort([1, 2, 3, 4, 5, 3, 4, 6, 8, 2]))

上述的代码,是最基础的冒泡排序。
实现原理就是:双重 for 循环,内层的循环实现相邻的两项进行对比,外层循环每执行完一次,都会筛选出当前数组中最大的项。

手写冒泡排序2

function bubbleSort2(arr) {
  var i = arr.length - 1

  while (i > 0) {
    var index = 0

    for (var j = 0; j < i; j++) {
      if (arr[j] > arr[j + 1]) {
        index = j
        var temp = arr[j]
        arr[j] = arr[j + 1]
        arr[j + 1] = temp
      }
    }
    i = index
  }

  return arr
}

console.log(bubbleSort2([1, 2, 3, 4, 5, 6, 7, 8, 3, 4, 5, 2, 1, 4]))
// [1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 7, 8]

// 从后向前遍历,记录最后一个交换的位置。节约不用交换的步骤的时间。

上述的代码,是优化后的冒泡排序。
实现原理:双层循环遍历,内层循环实现了相邻两项的对比,相对于 手写冒泡排序1,它会记录最后交换位置的索引。外层循环变成了从后向前遍历,并且跳过没有被交换的索引。

我的思考?

  • 对于循环的场景,不要太过于依赖 for 循环。某些场景,while 更加合适和好用。
  • 优化的思路可以多考虑考虑,去除无用的循环次数?

快速排序

var quickSort = function (arr) {
  if (arr.length <= 1) {
    return arr
  }

  var left = []
  var right = []
  var point = Math.floor(arr.length / 2)
  var pointElement = arr.splice(point, 1)[0]

  for (var i = 0; i < arr.length; i++) {
    if (arr[i] < pointElement) {
      left.push(arr[i])
    } else {
      right.push(arr[i])
    }
  }
  return quickSort(left).concat([pointElement], quickSort(right))
}

var arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]

console.log(quickSort(arr))

上述的代码,是快速排序。
实现原理:for 循环加递归,每次递归从数组中间抽取一项,比中间项小的项,放左侧数组,比中间项大的项,放右侧数组。递归到数组长度为 1 的情况返回数组。

我遇到的问题?

自己手写这里的代码的时候,这里的取中间元素,我没有使用 splice,将项截取出来。

var pointElement = arr.splice(point, 1)[0]
var pointElement = arr[point]

如果不取出中间的元素,假如:获取到的中间元素是最大的或者最小的元素。 那么左右两个数组会出现 [] [1,2,3,…]的情况,无限递归处理 [1,2,3,…] 就会陷入死循环,直到爆栈。

选择排序

function selectionSort(arr) {
  for (var i = 0; i < arr.length - 1; i++) {
    var minIndex = i

    for (var j = i + 1; j < arr.length; j++) {
      if (arr[j] < arr[minIndex]) {
        minIndex = j
      }
    }
    var temp = arr[i]
    arr[i] = arr[minIndex]
    arr[minIndex] = temp
  }

  return arr
}
var arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
console.log(selectionSort(arr)) //[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

上述的代码,是选择排序。
实现原理:双层 for 循环,内层每循环一次,会找出一个最小值,然后存储在头部。直到最后一项。

我遇到的问题?

  • 注意外层循环的边界值,由于内层循环总是从后一项开始选择,所以外层循环需要最大值需要减一。
  • 注意,最小索引 minIndex = i,每次比较的值是 i

插入排序

function insertionSort(arr) {
  for (var i = 1; i < arr.length; i++) {
    var key = arr[i]
    var j = i - 1

    while (j >= 0 && arr[j] > key) {
      arr[j + 1] = arr[j]
      j--
    }
    arr[j + 1] = key
  }

  return arr
}
var arr2 = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
console.log(insertionSort(arr2)) //[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

上述的代码,是插入排序。
实现原理:双层循环,内层循环会将数组每一项向后移,直到匹配到满足条件的数据,将其插入对应的数组位置。

我遇到的问题?

我在手写这个代码的时候,没有定义 key,即: var key = arr[i],代码出错。

因为 var j = i - 1, 然后循环中会修改 arr[j + 1]的值,导致后续赋值都将不准确。

function insertionSort(arr) {
  for (var i = 1; i < arr.length; i++) {
    var key = arr[i]
    var j = i - 1

    while (j >= 0 && arr[j] > key) {
      arr[j + 1] = arr[j]
      j--
    }
    arr[j + 1] = key
  }

  return arr
}

var arr2 = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
console.log(insertionSort(arr2)) //[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

end

  • 目前仅考虑熟练盲写,满足日常编程的需求,加油!
  • 本文编写时间: 2022/11/17-2022/11/19
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lazy_tomato

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值