简单的冒泡、选择、快速排序以及斐波那契数列

133 阅读1分钟

冒泡排序

  • 思路:
    • 用数组的每一个元素和下一个元素比较大小,如果当前的元素比下一个元素大,那就互换数组中的位置,继续和下一个比较
const popSort = arr => {
  // arr.length - 1
  // 因为在嵌套的排序中,通过比较大小,前后元素会互换,所以不必执行最后一次循环
  // 并不是必须的,只是为了减少时间复杂度
  for (let i = 0; i < arr.length - 1; i++) {
    // arr.length - 1 - i
    // 原理同上
    for (let j = 0; j < arr.length - 1 - i; j++) {
      if (arr[j] > arr[j + 1]) {
        let temp = arr[j]
        arr[j] = arr[j + 1]
        arr[j + 1] = temp
      }
    }
  }

  return arr
}

选择排序

  • 思路
    • 选择排序和冒泡排序有一点像,但是区别在于
      • 冒泡:每次和相邻元素比较,然后互换位置
      • 选择:每次查找最小元素,然后和当前元素互换位置
let selectSort  = arr => {
  for (let i=0; i<arr.length -1; i ++) {
    // 用于获取满足嵌套循环条件的下标
    let index = i
    // 这里是关键,选择排序,只循环还未排序的数组,所以此处j 永远比i 大 1
    for (let j = i + 1; j<arr.length; j ++) {
      // 每次满足arr[j] < arr[index] 更新index
      // 比如例子传入的数组中,第一次交换的过程如下
      // 外层第一次循环 元素为29,此时index = 0
      // 当内层循环元素为 10 时,10 < 29,此时index=3
      // 当内层循环下一步循环到 9 时,就是9 和 10 对比,此时index = 4
      // 依次类推,每次循环,查找最小的元素,然后用外层循环的元素和当前获取到最小元素的位置互换
      if (arr[j] < arr[index]) {
        index = j
      }
    }
    
    // 用获取到的下标取出当前循环的元素
    // 交换当前操作的元素和满足条件的元素 的位置
    let temp = arr[i]
    arr[i] = arr[index]
    arr[index] = temp
  }

  return arr
}

console.log(selectSort([29, 40, 34, 10, 9, 18]))


快速排序

  • 思路:
    • 取出数组的中间值,并且在此时要注意要修改元数组
    • 循环数组,将比中间值小的元素放到left 数组,否则放入right 数组
    • 递归调用
const quickSort = (arr) => {
  // 如果数组长度小于2 则返回传入的数组
  if (arr.length < 2) {
    return arr
  }
  // 中间元素下标
  const midIndex = ~~(arr.length / 2)
  // 中间元素,从传入的arr 中取出,并且修改arr
  const midItem = arr.splice(midIndex, 1)
  // 左边数组、右边数组
  const left = []
  const right = []
  for (let i = 0; i < arr.length; i++) {
    // 比中间元素小的放进左边数组,其他的进入右边数组
    if (arr[i] < midItem[0]) {
      left.push(arr[i])
    } else {
      right.push(arr[i])
    }
  }
  // 递归调用,再次分组,直到传入的数组只有一个元素
  return [...quickSort(left), ...[...midItem, ...quickSort(right)]]
}

斐波那契数列

  • 定义
    • 数列第1和第2项为1,从第3项开始,每一项都等于前两项之和
  • 举例
    • 1、1、2、3、5、8、13、21、34、...,n
  • 求第n 项的值
// 最简单的写法
let fib = (n) => {
  if (n < 3) {
    return 1
  }

  return fib(n - 1) + fib(n - 2)
}

// 上面方法重复计算次数太多,过于消耗性能
// 用数组保存每次计算的值,减少计算次数,用占用内存空间减少计算时间
const fib1 = (n) => {
  const arr = []
  arr[0] = 0
  arr[1] = 1
  for (let i = 2; i <= n; i++) {
    arr[i] = arr[i - 1] + arr[i - 2]
  }

  return arr[n]
}

// 继续优化
// 减少了存储数据量,优化存储空间
const fib2 = (n) => {
  let a = 0,
    b = 1,
    c

  if(n === 0) {
    return 0
  }

  for(let i=2; i<n; i++) {
    c = a + b
    a = b
    b = c
  }

  return b
}