链表式节点数据查找,与地址树数据算法
伪树
- 已知后端数据结构如下,要求只返回最里面的id=8,获得最里面那个节点,用name组织的节点路径
root/北京市/西城区/xx居委会
let root = [
id: 5,
name: "root",
children: [{
id: 6,
name: "北京市",
children: [{
id: 7,
name: "西城区",
children: [{
id: 8,
name: "xx居委会"
}]
}]
}]
]
思路
- 循环节点,发现子节点,则变更节点指针位置指向一个节点
- 为避免死循环,使用计时变量
i
及匹配条件跳出 - 上述源数据实为一个单链表,每个节点只有一个子节点
代码
此法适合单链表,即只有一个前驱后继的情况查找
示例查找 id 为8 的路径
let i = 1
let res = []
let searchId = 8
levelNode.children = root
while (true && i < 50) {
if (levelNode.children) {
levelNode = levelNode.children[0]
}
// 记录查找路径,由于id是唯一,故从根到指定id的路径是唯一
// 当前层路径查找
res.push(levelNode.name)
// 找到退出
levelNode.id == searchId && break
i++
}
console.log(res)
问题
上述结构,若某个节点存在多个子节点,在非同辈节点的首位节点查找则会出错
因此对下面源数据比如id为7,8,9会无能为力
[{
id: 5,
name: "root",
children: [{
id: 6,
name: "北京市",
children: [{
id: 10,
name: "东城区"
},
{
id: 7,
name: "西城区",
children: [
{
id: 8,
name: "xx居委会"
},
{
id: 9,
name: 'xx街道'
}]
}]
}]
}]
分析
- 叶子节点直接返回 id
- 同辈节点遍历
- 发现有孩子的直接交给内层函数处理,其返回的是内层值
- 将根节点包装成无父无标识的子组,否则根,需自行找补
关键分清当前域环境下的节点,与子节点环境的指向
叶子节点直接处理,指向子节点组交给内层循环处理
递归遍历,解包
方案
为便于直观过滤,将返回指定id所经过的路径节点列表
function queryPathByID(nd, id) {
for (let i = nd.children.length - 1; i >= 0; i--) {
const e = nd.children[i];
// 2.进入下一级
if (e.children) {
// 3. 移动指针进入 当前节点+下一层节点
return [e.id, ...queryPathByID(e, id)]
} else if (e.id == id) {
// 4. 叶子节点元素
return [e.id]
}
}
}