Javascript实现冒泡排序、插入排序、选择排序、归并排序

一、冒泡排序

在开始学习排序算法的时候最先学习的都是冒泡排序,它是比较简单的一个算法,也是性能最差的。

冒泡排序比较任何两个相邻的元素,如果第一个比第二个大,则交换他们的位置。元素一直向上移动直至正确的顺序,就犹如气泡一样向上冒,故叫冒泡排序。时间复杂度为O(n^2)。

代码实现:

let bubbleSort = (list) => {
  let arr = [...list] // 重新拷贝一份
  for (let i = 0; i < arr.length; i++) {
    for (let j = 0; j < arr.length - i; j++) {
      if (arr[j] > arr[j+1]) {
        [arr[j], arr[j+1]] = [arr[j+1], arr[j]] // ES6语法,交换两个元素的值
      }
    }
  }
  return arr // 返回排序后的数组
}
let list = [1,2,4,23,52,3,71,18,9]
let list1 = [1,2,3,4,5,6,7,8,9]
console.log(bubbleSort(list)) // [ 1, 2, 3, 4, 9, 18, 23, 52, 71 ]
console.log(bubbleSort(list1)) // [1,2,3,4,5,6,7,8,9]

但是上面的代码会有一些问题,比如像list1这样的数组本来就是一个排好序的数组,但是任然会一直执行循环语句,
这时候我们需要设置一个标识(flag)来表示是否有arr[j] > arr[j+1]的情况。

let bubbleSort2 = (list) => {
  let arr = [...list]
  let flag = true
  for (let i = 0; i < arr.length; i++) {
    for (let j = 0; j < arr.length - i; j++) {
      if (arr[j] > arr[j+1]) {
        [arr[j], arr[j+1]] = [arr[j+1], arr[j]]
        flag = false // 如果有进行此步操作则将flag设为false
      }
    }
    if (flag) { // 如果flag为true,表示没有进行换位操作,排序已经完成则终止循环
      break
    }
  }
  return arr
}

二、选择排序

选择排序的大致思路是先找出数组中最小的值并将其放在第一位然后再找出第二小的值,以此类推。时间复杂度为O(n^2)。

let selectionSort = function (list) {
  let arr = [...list]
  let len = arr.length
  let indexMin // 记录最小数的索引
  for (let i = 0; i < len; i++) { // 外循环
    indexMin = i // 先假定第一个为数组最小的值,为最小数索引赋值
    for(let j = i; j < len; j++) { // 内循环,注意j=i,因为每次循环是从已经确定的最小值后一个数开始
      if (arr[indexMin] > arr[j]) { // 如果后面的数小于先前假定的最小值
        indexMin = j // 则让最小数索引重新赋值
      }
    }
    if (i !== indexMin) { // 判断,然后交换位置
      [arr[i], arr[indexMin]] = [arr[indexMin], arr[i]]
    }
  }
  return arr
}

let list = [1,23,4,23,2,342,141,12]
console.log(selectionSort(list))

三、插入排序

插入排序的思想先维护一个已经排序好了的子数组,再将后面的元素做为待插入项与排序好的数组进行比较,插入到合适的位置。时间复杂度为O(n^2)。

let insertSort = (list) => {
  let array = [...list]
  let j,tmp // 用j来操作排序好的子数组,tmp记录将要插入的项
  for (let i = 1; i < array.length; i++) {                  
  // 从第2项开始,因为我们认为第1项是排序好的子数组
    j = i 
    tmp = array[i] // 记录待插入的项
    while (j > 0 && array[j - 1] > tmp) { // 
    // 从最后一项开始遍历已经排序好的数组,和待插入项比较
      array[j] = array[j-1] // 如果有大于待插入项的则交换位置
      j --
    }
    // 注意,在循环终止后并没有给array[j]赋值
    array[j] = tmp // 最后将待插入的项插入到循环终止的位置
  }
  return array
}
let list = [1,23,4,23,2,342,141,12]
console.log(insertSort(list))

在排序小型数组时,插入排序比冒泡排序和选择排序的性能要好一些。数组的sort()方法使用的是插入排序和快速排序结合的排序算法。

四、归并排序

归并排序是一种分治算法。其核心思想是将数组分为较小的数组,直到只有1个元素,接着将小的数组归并成较大的数组,直到只有一个数组,则排序完成。时间复杂度为O(nlogn)

要实现该算法,我们使用递归函数,将分出的较小数组依此入栈。

let mergeSort = function (list) {
  let array = [...list]
  if (array.length === 1) {
    return array // 递归的出口
  }
  let mid = Math.floor(array.length / 2)
  let left = array.slice(0,mid)
  let right = array.slice(mid, array.length)
  return merge(mergeSort(left), mergeSort(right)) // 依此将函数压入执行栈
}
// 在开始调用该函数的时候先取出执行栈栈顶元素,则left和right至少有一个的长度为1
let merge = function (left, right) {
  let result = []
  let il = 0
  let ir = 0
  while (il < left.length && ir < right.length) { // 依此比较两个数组中值的大小将较小的值插入数组
    if (left[il] < right[ir]) {
      result.push(left[il++])
    } else {
      result.push(right[ir++])
    }
  }
  while (il < left.length) { // 剩余left数组还没有归并
    result.push(left[il++])
  }
  while (ir < right.length) { // 剩余right数组hai'o'm
    result.push(right[ir++])
  }
  return result
}

let list = [1,23,4,23,2,342,141,12]
console.log(mergeSort(list))
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值