算法入门
1.如何找到两个数中较小的数字
- 数据结构
用数组[a,b]表示两个数字 - 编程知识
问号冒号表达式 ?: - 代码
let minOf2 = numbers => //定义numbers是一个长度为2的数组
numbers[0] < numbers[1] ? numbers[0] : numbers[1]
- 代码优化
析构赋值:将结构拆开,分开赋值
直接将数组放入括号中,数组第一项命名为a,第二项命名为b
let minOf2 = ([a,b]) => a < b ? a : b
- 调用
minOf([1,2])
minOf.call(null,[1,2])
:(推荐这个)第一个参数是this,没有就写null
算法就是把你解决问题的思路表示出来
1.1 现成API(函数)
- JS内置了Math.min
Math.min(1,2)
接收两个数字
Math.min.call(null,1,2)
不用this,call调用法
Math.min.apply(null,[1,2])
和call的唯一区别就是后面是数组
注意:如果call后面加数组则是把数组当成了一项整体来看,而apply是分开来看 - 关于Math
看起来像Object一样的构造函数
实际上Math只是一个普通对象
这是唯一的特例:首字母大写是构造函数
1.2 三个数字找出最小的那个
- 代码
调用两次minOf(注意:不是递归,因为minOf3调用的是minOf2,不是自身)
let minOf3 = ([a,b,c]) => {
return minOf([minOf2([a,b]),c])
}
或者
let minOf3 = ([a,b,c]) => {
return minOf([a,minOf2([b,c])]) //推荐这种,结构看起来更美观
}
- 推理
任意长度数组求最小值,都可以通过minOf2实现
let minOf4 = ([a,b,c,d]) => {
return minOf([a,minOf3([b,c,d])]) //推荐这种,结构看起来更美观
}
1.3 推广:求任意长度数组的最小值
- 代码
自己调用自己,这就是递归
let min = (numbers) => {
if(numbers.length > 2){
return min(
[numbers[0],min(numbers.slice(1))] //slice把第一个单独拿出来和后面的一堆求最小值
)
}else{
return Math.min.apply(null,numbers) //apply是把后面的数组展开
}
}
1.4 递归
- 特点
1.函数不停调用自己,每次调用的参数略有不同(每次min时形式完全一样,但参数不一样)
2.当满足某个简单条件时,则实现一个简单的调用
3.最终算出结果 - 理解
可以用代入法快速理解递归
可以用调用栈快速理解递归:进入下一行就是压栈,每次缩回来就是弹栈
2.选择排序
将正整数数组从小到大排序
不断选择最小的进行排序
2.1思路
- 用递归(更容易写出来,不能理解就用带入法)
- 用循环
2.2 递归思路——选择排序
- 长度为2的数组从小到大排序
let sort2 = ([a,b]) => a < b ? [a,b] : [b,a]
- 长度为3的数组从小到大排序
let sort3 = ([a,b,c]) => {
let index = minIndex([a,b,c]) //minIndex返回最小值的下标
let min = numbers[index]
numbers.splice(index,1)//从numbers里面删掉最小值
return [min].concat(sort2(numbers))//两个数字连接起来
}
minIndex
取巧代码(后续会教其他的):
let minIndex = (numbers) => numbers.indexOf(min(numbers))
有bug:如果有两个最小值,就只会返回第一个最小值的下标- 长度为4的数组排序
let sort4 = (numbers) => {
let index = minIndex(numbers)
let min = numbers(index)
numbers.splice(index,1)
return [min].concat(sort3(numbers))
}
2.3 推广
- 任意长度的数组排序
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.revers()
}
}
- 递归要用带入法
3.代码会错——如何调试
用console.log调试
- 调用栈
函数调用了函数,前面一个函数就会被压到栈里去,下图就是压栈的过程
- 当代码运行结果出现错误,就把每一步的结果用console.log打出来,看哪一步结果开始不对
注意:括号里是反引号
console.log(`min: ${min}`)