掌握递归(recursion)基本就是懂了编程中的
- 函数调用栈
- 作用域链
- 引用类型、基本类型
- 传递引用、值传递
反之如果二叉树前序、后序遍历也看不懂的话上边三条知识点并不清楚
递归为什么难懂 forloop是线性的,符合大脑思考,很容易想象到最终的结果 递归的难点在于分治上,分治是树状的,第一眼根本看不到最终值,总是担心是不是会漏掉一些; 人肉做树状递归非常痛苦,而在一般教程上递归上来就是树状递归,斐波那契、汉诺塔、二叉树遍历,这种都是非线性树状的递归,而一般编程基础薄弱的调用栈都说不清楚,别说做一个分治递归了。
而在工程中没用那么多分治树状递归,线性递归已经可以让代码优雅的不得了。
工程代码中递归的实践
转换省市区
需求描述
根据地区编码转换为 省 市 区 例如 地区编码:六位 例如110102 数据表格式
// 数据出处
// https://github.com/withwz/China-area-data-json.git
export default [{
"value": "110000",
"label": "北京市",
"children": [{
"value": "110100",
"label": "北京市",
"children": [{
"value": "110101",
"label": "东城区"
}, {
"value": "110102",
"label": "西城区"
}
...
}]
...
}]
...
}]
答案
思路
六位数字的地区编码,前两位是省,中间两位是市,最后两位是县区
- 如果用循环的话也可以,嵌套三层循环呗,但如果再加上镇、乡、村,难道要嵌套六层循环吗。不够优雅。
- 递归方案:观察数据,是一个三维数组,每一个数组中的对象都有一个children属性,值是一个同外层数组相同格式的数组,那就又children属性则继续向下走呗,终止条件是走到最后一位地区编码
核心
- 递归
- 双指针滑动窗口
- 字符串是值传递
- 出栈时返回值
```typescript
/**
- 根据区代码在area.js中的数据拿到省市区 *
- @param list 地区
- @param code 六位地区代码 省 市 区
- @param start 滑动指针两位两位向前滑
- @param end 滑动指针
- @param res 省 市 区
*/
function getArea(list: Array
, code: string, start: number,
if(end > 6) return res const _code = code.toString().slice(start, end) for (let i = 0; i < list.length; i++) { if (_code === list[i].value.slice(start, end)) {end: number, res: any): any {
}res = res + list[i].label + ' ' if (list[i]?.children !== undefined) { return getArea(list[i].children, code, start + 2, end + 2, res) } else { return res } } }
getArea(area, record, 0, 2, ‘’)
<a name="bCffx"></a>
### 扁平化数组
**描述**
> [1, [2, [3, [4]], 5]] ==> [1, 2, 3, 4, 5]
思路
- 数组是引用传递,不会因为进入新调用栈或者出栈而内容改变;
- 如果是数组则继续向下走
```javascript
function isArrType(params) {
return Object.prototype.toString.apply(params) === '[object Array]'
}
function flatten(arr, ans) {
for (const iter of arr) {
if (isArrType(iter) === true) {
flatten(iter, ans)
} else {
ans.push(iter)
}
}
return ans
}
// 测试
let arr = [1, [2, [3, [4]], 5]]
const res = flatten(arr, [])
console.log("res:", res)
总结
递归就是函数调用自己调自己;
常见应用做法是
- js中可以通过数组对象是引用传递,进入新的调用栈中不会重置对象值的特性不断修改完善值,思想可以参考先序遍历;
- 也可以把结果返回出来,在最顶层调用完毕后,最顶层调用栈返回给第二层,第二层给第三层…第四层…第五层,在函数出栈的时候不断修改完善值,思想同后续遍历差不多。
- 比如一个基本类型的字符串,在递归中不断的传递