1. 题目内容
前几天在刷题的时候,遇到下面这个题,自己卡了好久,特此记录一下。 题目内容如下
有一个数据结构如下, 请实现一个函数, 检查依赖中是否出现循环依赖,而且要求可以检查子依赖
const dependencies = [
{
name: "a",
dependencies: 'b'
},
{
name: "b",
dependencies: 'c'
},
{
name: "c",
dependencies: [{
name: "d",
dependencies: 'a'
}]
},
]
2. 解题思路
递归解法
首先用人脑模拟一下遍历过程, 从第一个元素开始遍历,
- 那么a依赖b, b依赖c, 此时依赖链条为 a => b => c
- c的依赖是个数组, 所以需要查找子依赖, 子依赖中d依赖于a, 此时出现了循环依赖, 此时依赖链条为 a=>b=>c=>d=>a。
观察可知, name 为d的depenndencies 为a, a是第一个元素的name。
由此可知, 我们可以把遍历过的name放到一个数组或者set中, 如果遍历到某一个依赖,发现本依赖的dependencies在这个数组中存在, 那么就说明出现了循环依赖。此时应该中断遍历。
代码如下:
// 根据当前组件的dependencies, 查找下一个
const findDep = (deps, dep) => {
return deps.find(d => d.name === dep.dependencies);
}
/**
* 检查循环依赖
* @param {*} deps
*/
const checkDeps = (deps) => {
// 遍历过的name
let visited = [];
// 是否有循环依赖的标志
let hasCircle = false;
const check = (deps, dep) => {
if (visited.includes(dep.dependencies)) {
hasCircle = true
// 当出现循环依赖时,中断调出函数
return;
}
visited.push(dep.name);
if (typeof dep.dependencies == 'string') {
// 查找下一个元素, 并递归的检查下一个元素依赖项
const depItem = findDep(deps, dep);
if (depItem) {
check(deps, depItem);
}
} else if (dep.dependencies instanceof Array) {
// 如果是数组, 则遍历子依赖
const { dependencies } = dep
dependencies.map((one) => {
check(dependencies, one);
})
}
return hasCircle;
}
for (let i = 0; i < deps.length; i++) {
const dep = deps[i];
check(deps, dep);
if (hasCircle) {
break;
}
}
return hasCircle;
}
注: 上面之所以定义了一个hasCircle的变量, 是因为在递归中return 要处理好几个地方, 所以用变量来穿透递归省事点。