一、求最小值的函数
(一)必备知识
1.数据结构: 数组[1,2,3,4]
2.编程知识: ?:表达式
(二)从两个数中找出最小的那个
- 给一个二元数组
- 如果第一个数小于第二个数
- 就输出第一个数
- 否则输出第二个数
1.第一版
let minOf2 = (numbers) => {
if (numbers[0]<numbers[1]) {return numbers[0] }
else {return numbers[1]}
}
2.第二版代码:优化
let minOf2 = (numbers) => number[0]<number[1]?number[0]:number[1]
3.第三版代码: 析构赋值
let minOf2 = ([a,b]) => a<b ? a : b
4.现成API
JS内置了Math.min
Math.min(1,2) //1
Math.min.call(null,1,2)
Math.min.call(null,[1,2])
关于Math
- 看起来Math像Object一样是构造函数
- 实际上Math只是一个普通对象
- 这是唯一的特例:首字母大写是构造函数
(三)从三个数中找出最小的那个
- 给一个三元数组
- 我们已经会从两个数中找最小值了
- 那就先找出数组中后两个数的最小值
- 再从数组中第一个数和刚才得到的最小值两者中找最小值
1.第一版代码
let minOf3 = numbers => {
return minOf2([numbers[0],minOf2(numbers.slice(1))])
}
2.第二版代码:析构赋值
let minOf3 = ([a,b,c]) => minOf2([a,minOf2([b,c])])
(四)从四个数中找出最小的那个
- 给一个四元数组
- 我们已经会从三个中找出最小数
- 那就先从数组的后三个中找出最小数
- 在从数组中第一个数和上面那个最小数两者中找出最小数
1.第一版代码
let minOf4 = ([a,b,c,d]) => minOf2([a,minOf3([b,c,d])])
(五)发现规律
- 求一个n元数组中的最小值
- 先把第一个数提出来
- 再求出剩下的的最小值
- 最后求出第一个数和后来求出的那个最小值两者的最小值
(六)任意长度数组求最小值
第一版代码
let min = (numbers) => {
return min([numbers[0],min(numbers.slice(1))])
}
但是这个代码会死循环不停调用自己,应该添加一个终止条件
第二版代码
let min = (numbers) => {
if(numbers.length>2){ //当数组的长度大于2时才如此循环调用自己
return min([numbers[0],min(numbers.slice(1))])
}
else { //当数组长度小于等于2时就用现成的简单的一个函数执行
return Math.min.apply(null,numbers)
}
}
这就是递归
二、递归
1.特点
- 函数不停调用自己,每次调用的参数略有不同
- 当满足某个简单条件时,则实现一个简单的调用
- 最终算出结果 2.理解 可以用代入法快速理解递归 可以用调用栈快速理解递归
递进 min([2,4,3,1])
递进 4>2 === min([2,min([4,3,1])])
递进 3>2 === min([2,min([4,min([3,1])])])
递进 2<=2 === min([2,min([4,Math.min.apply(null,[3,1])])])
回归 === min([2,min([4,1])])
回归 2<=2 === min([2,Math.min.apply(null,[4,1])])
回归 === min([2,1])
回归 2<=2 === Math.min.apply(null,[2,1])
回归 === 1
递进 sort([2,4,3,1])
递进 4>2 === [1,sort([2,4,3])]
递进 3>2 === [1,[2,sort([4,3])]]
回归 2<=2 === [1,[2,[3,4]]]
回归 2<=2 === [1,[2,3,4]]
回归 2<=2 === [1,2,3,4]
三、将正整数数组从小到大排序(选择排序的递归写法)
(一)思路
- 数据结构:数组
- 逻辑:循环、递归
(二)对两个数进行排序
- 给定个二元数组
- 如果第一个数大于第一个数
- 就两者调换位置
- 否则不变
第一版代码
let sort2 = ([a,b]]) => a>b ? [b,a] : [a,b]
第二版代码
let sort2 = numbers => numbers[0]>numbers[1] ? numbers.reverse() : numbers
(三)对三个数进行排序
- 给定一个三元数组
- 先选出最小值
- 我们已经知道两元数组怎么排序
- 那么就可以让剩下的两位排序
- 最后把最小值和上面的两位排序结合起来就行了
第一版代码:析构赋值
let sort3 = ([a,b,c]) => {
return[min([a,b,c]),sort2(???)]
}
发现无法将最小值从数组里删掉
第二版代码
let sort3 = (numbers) => {
let index=numbers.indexOf(min(numbers)) //找出最小值的下标,并且命名为index
let min = numbers[index] //找出最小值并且命名为min
numbers.splice(index,1) //从数组中删去最小值,因此该数组变成了一个新数组了
return [min].concat(sort2(numbers))
}
(四)对四个数进行排序
- 给定一个四元数组
- 找出最小值
- 剩下的三个数字排序
- 把最小值和上面的排序结合起来就行了
代码
let sort4 = (numbers) => {
let index=numbers.indexOf(min(numbers)) //找出最小值的下标,并且命名为index
let min = numbers[index] //找出最小值并且命名为min
numbers.splice(index,1) //从数组中删去最小值,因此该数组变成了一个新数组了
return [min].concat(sort3(numbers))
}
(五)总结规律:对N个数从小到大排序
每次找到最小的数放前面,然后对剩下的数组做同样的事情
- 给定一个数组
- 先找出最小值(因为要排在第一个)放在最前面
- 剩下的数组进行排序(套娃开始了)
- 把最小值和上面的排序结合起来就行了。
- 排到什么时候不排了呢?排到数组里只剩下两个数就不用排了,直接比较谁大谁小。
第一版代码
let sort = (numbers) => {
let index=numbers.indexOf(min(numbers)) //找出最小值的下标,并且命名为index
let min = numbers[index] //找出最小值并且命名为min
numbers.splice(index,1) //从数组中删去最小值,因此该数组变成了一个新数组了
return [min].concat(sort(numbers))
}
死循环又出现了
第二版代码
let min = (numbers) => {
if(numbers.length > 2){
return min(
[numbers[0], min(numbers.slice(1))]
)
}else{
return Math.min.apply(null, numbers)
}
}
let minIndex = (numbers) =>
numbers.indexOf(min(numbers))
let sort = (numbers) => {
if(numbers.length > 2){ //当数组的长度大于2时才如此循环调用自己
let index = minIndex(numbers) //拿到numbers最小值的下标
let min = numbers[index] //拿到最小值
numbers.splice(index, 1) //从numbers里删除 min(最小值)
return [min].concat(sort(numbers))
}else{ //当数组长度小于等于2时就用现成的简单的一个函数执行
return numbers[0]<numbers[1] ? numbers : numbers.reverse()
}
}
四、找出数组中最小值的下标
方法一
取巧的办法,以后会有更好的
let minIndex = (numbers) => numbers.indexOf(min(numbers))
方法二:循环
- 首先让index就是表示最小值的下标。首先默认第一个数就是最小值。那么刚开始index=0
- 从数组中第二个数开始,每个数都和最小值比较,如果哪个数比最小值还小,就让这个数成为新的最小值。
- 直到数组中最后一个数和最小值比完就可以结束了。
let minIndex = (numbers) =>
let index = 0
for(let i=1; i<numbers.length; i++){
if(numbers[i] < numbers[index]){
index = i
}
}
return index
}
五、选择排序的循环写法
思路不变:
-
每次找到最小的数放前边,然后i++
-
但是是在新的波浪线数组里找到最小的,放到波浪线新数组的最前面。
-
对应原数组的话,那就是在原数组生成的波浪线数组里面找到最小的,放到第i个。
代码:
let sort = (numbers) => {
for (let i = 0; i < numbers.length - 1; i++) {
let index = minIndex(numbers.slice(i)) + i //找到波浪线数组中的最小值,在原数组中对应的下标
if (index !== i) { swap(numbers, index, i) } //把第i个和最小的交换
}
return numbers
}
//辅助函数,交换一个数组里面两个元素
let swap = (array, i, j) => {
let temp = array[i]
array[i] = array[j]
array[j] = temp
}
//辅助函数,找到一个数组里的最小值的下标
let minIndex = (numbers) => {
let index = 0
for (let i = 1; i < numbers.length; i++) {
if (numbers[i] < numbers[index]) {
index = i
}
}
用log看,更明显
let sort = (numbers) => {
for (let i = 0; i < numbers.length - 1; i++) {
console.log(`----`)
console.log(`i: ${i}`)
let index = minIndex(numbers.slice(i)) + i
console.log(`index: ${index}`)
console.log(`min: ${numbers[index]}`)
if (index !== i) {
swap(numbers, index, i)
console.log(`swap ${index}: ${i}`)
console.log(numbers)
}
}
return numbers
}
代码出错解决方法
用console,log
调试