排序算法

224 阅读3分钟

把你解决一个问题的思路用代码表示出来,就是算法。只要你是代码表示思路,那这个代码就是你的算法。 你不会写代码一定是因为你不理解思想,不可能理解思想不会写代码,只有一种情况——会写代码但是不知道思想。 要多错,通过打 log 找出自己错在哪里,以后你就不会再错了。所以新人一定要尽力,错了,加 log,发现又错了,再加 log,又错了,再加 log,不停地加了 log 错加了 log 错。你就这样不停地试,等你把所有能错的都试完了,你就是大师。

算法入门(上)——算法比你想象中简单

小试牛刀——如何找出两个数中较小的那一个

必备知识

数据结构

  • 用数组[a,b]表示两个数字
  • 你能想到这一点,就说明你在使用数据结构

编程知识

  • 问好冒号表达式?:

两个数找出较小的那个

代码

let minOf2=(numbers)=>{
  if(numbers[0]<number[1]){
    return number[0]
  }else{
    return number[1]
  }
}

优化代码

let minOf2=numbers=>
  numbers[0]<number[1]?number[0]:numbers[1]

再优化代码

let minOf2=([a,b])=>a<b?a:b

这种写法叫做析构赋值,之后的课程会反复使用

调用

  • minOf2[1,2] // 1 这是小白调用法
  • minOf2.call(null,[1,2]) // 1 这是高手调用法

现成 API

JS 内置了 Math.min

  • Math.min(1,2) // 1
  • Math.min.call(null,1,2) // 1
  • Math.min.apply(null,[1,2]) // 1

关于 Math

  • 看起来 Math 像 Object 一样是构造函数
  • 实际上 Math 只是一个普通对象
  • 这是唯一的特例:其它情况首字母大写都是构造函数

举一反三——两个数变成三个数

三个数找出最小的那个

代码

let minOf3=([a,b,c])=>{
  return minOf2([minOf2([a,b]),c])
}

或者

let minOf3=([a,b,c])=>{
  return minOf2([a,minOf2[b,c]])
}

推理,任意长度数组求最小值,都可以通过 minOf2 实现

let minOf4=([a,b,c,d])=>{
  return minOf2([a,minOf3([b,c,d])])
}

推广——任意长度数组求最小值

找出最小的那个

代码

let min=(numbers)=>{
  return min([numbers[0],min(numbers.slice(1))])
}

这个代码会死循环不停调用自己,需要添加一个中止条件

代码

let min=(numbers)=>{
  if(numbers.length>2){
    return min([numbers[0],min(numbers.splice(1))])
  }else{
    return Math.min.apply(null,numbers)
  }
}

这就是递归

递归

特点

  • 函数不停调用自己,每次调用的参数略有不同
  • 当满足某个简单条件时,则实现一个简单的调用
  • 最终算出结果

理解

  • 可以用代入法快速理解递归
  • 可以用调用栈快速理解递归

升级——将正整数数组从小到大排序

排序算法

思路

  • 用递归实现
  • 用循环实现

递归思路——选择排序

小试牛刀——将长度为 2 的数组排序

代码

let sort2=([a,b])=>{
  if(a<b>){
    return [a,b]
  }else{
    return [b,a]
  }
}

优化代码

let sort2=([a,b])=>
  a<b?[a,b]:[b,a]

长度为 3 的数组排序

代码

let sort3=([a,b,c])=>{
  return [min([a,b,c]),sort2([???])]
}

我们发现无法将最小值从数组里删掉

改进代码

let sort3=(numbers)=>{
  let index=minIndex([a,b,c])
  let min =number[index]
  numbers.splice(index,1)//从numbers里删掉min
  return [min].concat(sort2(numbers))
}

minIndex

代码

let minIndex=(numbers)=>
  numbers.indexOf(min(numbers))

这是一个取巧的办法,利用 indexOf 来得到下标,以后会学更好的方法

长度为 4 的数组排序

代码

let sort4=(numbers)=>{
  let index=minIndex(numbers)
  let min=numbers[index]
  number.splice(index,1)
  return [min].concat(sort3(numbers))
}

推广——任意长度的数组排序

代码

let sort=(numbers)=>{
  let index=minIndex(numbers)
  let min=numbers[index]
  numbers.splice(index,1)
  return [min].concat(sort(numbers))
}

这会死循环……

代码

let sort=(numbers)=>{
  if(numbers.length>2){
    let index=minIndex(numbers)
    let min=numbers[index]
    numbers.splice(index,1)
    return [min].concat(sort(numbers))
  }else{
    return numbers[0]<numbers[1]?numbers:numbers.reverse()
  }
}

用代入法看看 sort([12,5,8,7,9])的过程

代码会错——用 console.log 调试

总结

求最小值

  • 2 个数
  • 3 个数
  • N 个数

排序

  • 2 个数
  • 3 个数
  • N 个数

用到的东西

  • 数组(只用到了一个数据结构,就是数组),提供的操作有:concat、splice、slice
  • 递归