JavaScript 嵌套对象结构中的递归树搜索

Vla*_*r84 9 javascript tree recursion json

我试图弄清楚如何在这个 JSON 对象中递归搜索节点。我尝试过一些东西但无法得到它:

var tree = {
    "id": 1,
    "label": "A",
    "child": [
        {
            "id": 2,
            "label": "B",
            "child": [
                {
                    "id": 5,
                    "label": "E",
                    "child": []
                },
                {
                    "id": 6,
                    "label": "F",
                    "child": []
                },
                {
                    "id": 7,
                    "label": "G",
                    "child": []
                }
            ]
        },
        {
            "id": 3,
            "label": "C",
            "child": []
        },
        {
            "id": 4,
            "label": "D",
            "child": [
                {
                    "id": 8,
                    "label": "H",
                    "child": []
                },
                {
                    "id": 9,
                    "label": "I",
                    "child": []
                }
            ]
        }
    ]
};
Run Code Online (Sandbox Code Playgroud)

这是我的非工作解决方案,这可能是因为第一个节点只是一个值,而孩子在数组中:

function scan(id, tree) {
    if(tree.id == id) {
        return tree.label;
    }

    if(tree.child == 0) {
        return
    }

    return scan(tree.child);
};
Run Code Online (Sandbox Code Playgroud)

ggo*_*len 12

您的代码只是缺少一个循环来检查child数组中节点的每个子节点。这个递归函数将返回label节点的属性,或者undefined如果标签不存在于树中:

const search = (tree, target) => {
  if (tree.id === target) {
    return tree.label;
  }
  
  for (const child of tree.child) {
    const found = search(child, target);
    
    if (found) {
      return found;
    }
  }
};

const tree = {"id":1,"label":"A","child":[{"id":2,"label":"B","child":[{"id":5,"label":"E","child":[]},{"id":6,"label":"F","child":[]},{"id":7,"label":"G","child":[]}]},{"id":3,"label":"C","child":[]},{"id":4,"label":"D","child":[{"id":8,"label":"H","child":[]},{"id":9,"label":"I","child":[]}]}]};

console.log(search(tree, 1));
console.log(search(tree, 6));
console.log(search(tree, 99));
Run Code Online (Sandbox Code Playgroud)

您还可以使用不会导致堆栈溢出的显式堆栈迭代执行此操作(但请注意,stack.push(...curr.child);由于扩展语法,速记可能会溢出某些 JS 引擎的参数大小,因此请使用显式循环或concat大量子数组) :

const search = (tree, target) => {
  for (const stack = [tree]; stack.length;) {
    const curr = stack.pop();
    
    if (curr.id === target) {
      return curr.label;
    }

    stack.push(...curr.child);
  }
};

const tree = {"id":1,"label":"A","child":[{"id":2,"label":"B","child":[{"id":5,"label":"E","child":[]},{"id":6,"label":"F","child":[]},{"id":7,"label":"G","child":[]}]},{"id":3,"label":"C","child":[]},{"id":4,"label":"D","child":[{"id":8,"label":"H","child":[]},{"id":9,"label":"I","child":[]}]}]};

for (let i = 0; ++i < 12; console.log(search(tree, i)));
Run Code Online (Sandbox Code Playgroud)

更通用的设计将返回节点本身,并让调用者访问该.label属性(如果他们愿意),或者以其他方式使用该对象。

请注意,JSON 纯粹是序列化(字符串化、原始)数据的字符串格式。一旦您将 JSON 反序列化为 JavaScript 对象结构,就像这里一样,它就不再是 JSON。