如何使用JavaScript在树中查找节点

Dav*_*ave 41 javascript

我有和object literal本质上是一个没有固定数量级别的树.我怎样才能在树中搜索特定节点,然后在javascript中以高效的方式返回该节点?

基本上我有一个像这样的树,并希望找到标题为'randomNode_1'的节点

var data = [
{
title: 'topNode',
 children: [
   {
       title: 'node1',
       children: [
       {
           title: 'randomNode_1'
       },
       {   
           title: 'node2',
           children: [
           {
               title: 'randomNode_2',
               children:[
               {   
                   title: 'node2',
                   children: [
                   {
                       title: 'randomNode_3',
                   }]
               }
               ]
           }]
       }]
   }
  ]
 }];
Run Code Online (Sandbox Code Playgroud)

ggr*_*ner 62

基于@Ravindra的回答得出这个答案,但是真正的递归.

function searchTree(element, matchingTitle){
     if(element.title == matchingTitle){
          return element;
     }else if (element.children != null){
          var i;
          var result = null;
          for(i=0; result == null && i < element.children.length; i++){
               result = searchTree(element.children[i], matchingTitle);
          }
          return result;
     }
     return null;
}
Run Code Online (Sandbox Code Playgroud)

然后你可以称之为:

var element = data[0];
var result = searchTree(element, 'randomNode_1');
Run Code Online (Sandbox Code Playgroud)


Fis*_*rdo 22

这是一个迭代解决方案:

var stack = [], node, ii;
stack.push(root);

while (stack.length > 0) {
    node = stack.pop();
    if (node.title == 'randomNode_1') {
        // Found it!
        return node;
    } else if (node.children && node.children.length) {
        for (ii = 0; ii < node.children.length; ii += 1) {
            stack.push(node.children[ii]);
        }
    }
}

// Didn't find it. Return null.
return null;
Run Code Online (Sandbox Code Playgroud)

  • 这应该是一个公认的答案,其他递归的答案倾向于stackoverflow,尤其是在javascript中 (9认同)
  • 我想当我在很多个月前写这么多的时候,我的思考过程是你会在这个方法中对节点做一些事情,而不是返回它。但谁能说得清呢?过去的我反复无常,容易出错。完全不像 Current Me ;) 但我现在改变了代码以返回一些东西。无论哪种方式,迭代解决方案的基本框架都在那里。 (2认同)

Eri*_*lli 6

这是一个使用Stack方法的迭代函数,其灵感来自FishBasketGordo的答案,但它利用了某些ES2015语法来缩短内容。它还允许选择从其开始搜索的父节点。

function search (title, parent) {
  const stack = [ parent ]
  while (stack.length) {
    const node = stack.pop()
    if (node.title === title) return node
    node.children && stack.push(...node.children)
  }
  return stack.pop() || null
}
Run Code Online (Sandbox Code Playgroud)

您可以这样简单地使用它:

let result = search('randomNode_1', data[0])
Run Code Online (Sandbox Code Playgroud)


sub*_*bbu 6

查找树中的节点:

假设我们有一棵树

let tree = [{
  id: 1,
  name: 'parent',
  children: [
    {
      id: 2,
      name: 'child_1'
    },
    {
      id: 3,
      name: 'child_2',
      children: [
        {
          id: '4',
          name: 'child_2_1',
          children: []
        },
        {
          id: '5',
          name: 'child_2_2',
          children: []
        }
      ]
    }
  ]
}];


function findNodeById(tree, id) {

   let result = null
   if (tree.id === id) {
        return tree;
   }

   if (Array.isArray(tree.children) && tree.children.length > 0) {
      tree.children.some((node) => {
        result = findNodeById(node, id);
        return result;
      });
   }
   return result;}
Run Code Online (Sandbox Code Playgroud)


Tim*_*ich 5

我的答案灵感来自FishBasketGordo的iterativ答案。它有点复杂,但也要灵活得多,您可以拥有多个根节点。

/**searchs through all arrays of the tree if the for a value from a property
 * @param aTree : the tree array
 * @param fCompair : This function will receive each node. It's upon you to define which 
                     condition is necessary for the match. It must return true if the condition is matched. Example:
                        function(oNode){ if(oNode["Name"] === "AA") return true; }
 * @param bGreedy? : us true to do not stop after the first match, default is false
 * @return an array with references to the nodes for which fCompair was true; In case no node was found an empty array
 *         will be returned
*/
var _searchTree = function(aTree, fCompair, bGreedy){
    var aInnerTree = []; // will contain the inner children
    var oNode; // always the current node
    var aReturnNodes = []; // the nodes array which will returned

    // 1. loop through all root nodes so we don't touch the tree structure
    for(keysTree in aTree) {
        aInnerTree.push(aTree[keysTree]);
    }
    while(aInnerTree.length > 0) {
        oNode = aInnerTree.pop();
        // check current node
        if( fCompair(oNode) ){
            aReturnNodes.push(oNode);
            if(!bGreedy){
                return aReturnNodes;
            }
        } else { // if (node.children && node.children.length) {
            // find other objects, 1. check all properties of the node if they are arrays
            for(keysNode in oNode){
                // true if the property is an array
                if(oNode[keysNode] instanceof Array){
                    // 2. push all array object to aInnerTree to search in those later
                    for (var i = 0; i < oNode[keysNode].length; i++) {
                        aInnerTree.push(oNode[keysNode][i]);
                    }
                }
            }
        }
    }
    return aReturnNodes; // someone was greedy
}
Run Code Online (Sandbox Code Playgroud)

最后,您可以使用如下功能:

var foundNodes = _searchTree(data, function(oNode){ if(oNode["title"] === "randomNode_3") return true; }, false);
console.log("Node with title found: ");
console.log(foundNodes[0]);
Run Code Online (Sandbox Code Playgroud)

而且,如果您想查找所有具有此标题的节点,则只需切换bGreedy参数即可:

var foundNodes = _searchTree(data, function(oNode){ if(oNode["title"] === "randomNode_3") return true; }, true);
console.log("NodeS with title found: ");
console.log(foundNodes);
Run Code Online (Sandbox Code Playgroud)