繁体   English   中英

如何使用递归返回从树根到目标的树节点的 ArrayList?

[英]How to return an ArrayList of tree nodes spanning from the tree root to a target using recursion?

这个项目的目标是分析谁在金字塔计划中受益。 PyramidScheme.java 是一个数据结构,它扩展了LinkedTree(LinkedTree.java 是一个非常标准的树类),传入Person(一个Person.java 是金字塔计划的参与者,类信息无关紧要)对象代替泛型。

我无法弄清楚的有问题的方法是 findNodeChain。 这个方法是 PyramidScheme.java 的一个成员,应该返回一个 MultiTreeNode 的 ArrayList(MultiTreeNode.java 是一个非常标准的树节点类)对象,是从吸盘中“受益”的人 - 即上面的每个节点傻逼。 这是相关代码(findNodeChain 在底部):

 /**
 * Initiates the recursive findNodeChain method to return a list of all
 * nodes that are above the node containing the target. This overload takes
 * a Person.
 *
 * @param sucker the individual from whom others above are benefitting
 * @return an ArrayList of individuals higher up in the hierarchy
 */
public ArrayList<MultiTreeNode<Person>>
        whoBenefits(Person sucker) {
    return findNodeChain(root, sucker);
}

/**
 * Initiates the recursive findNodeChain method to return a list of all
 * nodes that are above the node containing the target. This overload takes
 * a MultiTreeNode.
 *
 * @param sucker the individual from whom others above are benefitting
 * @return an ArrayList of individuals higher up in the hierarchy
 */
public ArrayList<MultiTreeNode<Person>>
        whoBenefits(MultiTreeNode<Person> sucker) {
    return findNodeChain(root, sucker.getElement());
}

/**
 * Similar to findNode, but rather than returning the node that contains the
 * target, instead returns a list of nodes above the one that contains the
 * target, in low to high level order.
 *
 * @param node the current node being examined
 * @param target the Person being searched for
 * @return an ArrayList of nodes that are directly above the target in the
 * hierarchy
 */
private ArrayList<MultiTreeNode<Person>>
        findNodeChain(MultiTreeNode<Person> node, Person target) {
    return findNodeChain(node, target, new ArrayList<>());
}

/**
 * Primary helper method for findNodeChain
 *
 * @param node the current node being examined
 * @param target the Person being searched for
 * @param helper the ArrayList people to be returned
 * @return an ArrayList of nodes that are directly above the target in the
 * hierarchy
 */
private ArrayList<MultiTreeNode<Person>>
        findNodeChain(MultiTreeNode<Person> node, Person target, ArrayList<MultiTreeNode<Person>> helper) {
    if (node.getElement().equals(target)) { 
        // If this node is the target, add it to the list and return.
        helper.add(node); 
        return helper;
    } else {            
        //For each child of this node...
        for (MultiTreeNode<Person> child : node.getChildren()) {
            //...Call this method, seeing if the child can find our target.
            helper.add(child);
            helper = findNodeChain(child, target, helper);
            //If it isn't null, then the child has found our target, and...
            if (helper.get(helper.size() - 1) != null) {
                return helper; //...The target is passed upwards.
            }
        }
        // If none of the children have the target, return the passed ArrayList
        return helper;
    }
}

我开始尝试通过将 findNodeChain() 与 LinkedTree.java 中的 findNode() 方法分开来解决这个问题:

/**
 * Finds the node that contains a target element. Calls the recursive
 * overload to search for target.
 *
 * @param target the element being searched for
 * @return the MultiTreeNode containing the target, or null if not found
 */
public MultiTreeNode<T> findNode(T target) {
    if (target == null) {
        return null;
    }
    return findNode(root, target);
}

/**
 * Finds the node that contains a target element. This checks the current
 * node, and if it is the target, returns it. Otherwise, it recursively
 * checks each of the current node's children, to see if they can find it.
 * If none of this node's children can find it either, then null is
 * returned.
 *
 * @param node the node currently being examined
 * @param target the element being searched for
 * @return the MultiTreeNode containing the target, or null if not found
 */
private MultiTreeNode<T> findNode(MultiTreeNode<T> node, T target) {
    //If this node is the one holding the target...
    if (node.getElement().equals(target)) {
        return node; //...Return this node, so it is passed upwards.
    } else { //Otherwise...
        MultiTreeNode<T> temp;
        //For each child of this node...
        for (MultiTreeNode<T> child : node.getChildren()) {
            //...Call this method, seeing if the child can find our target.
            temp = findNode(child, target);
            //If it isn't null, then the child has found our target, and...
            if (temp != null) {
                return temp; //...The target is passed upwards.
            }
        }
        //If none of the children found the target, return null.
        return null; //This signifies that no target was found.
    }
}

也试过这个:

/**
 * Similar to findNode, but rather than returning the node that contains the
 * target, instead returns a list of nodes above the one that contains the
 * target, in low to high level order.
 *
 * @param node   the current node being examined
 * @param target the Person being searched for
 * @return an ArrayList of nodes that are directly above the target in the
 * hierarchy
 */
private ArrayList<MultiTreeNode<Person>>
findNodeChain(MultiTreeNode<Person> node, Person target) {
    // Create the ArrayList here and pass its reference at each recursion
    ArrayList<MultiTreeNode<Person>> helper = new ArrayList<>();
    hasNodeChain(node, target, helper); // Pass the ArrayList
    return helper; // Return the passed around ArrayList. Yay for pass by reference!!

}

/**
 * Primary helper method for findNodeChain
 *
 * @param node   the current node being examined
 * @param target the Person being searched for
 * @param helper the pointer of the ArrayList of people to be returned
 * @return true if there is a path from node to target, false if not
 */
private boolean hasNodeChain(MultiTreeNode<Person> node, Person target, ArrayList<MultiTreeNode<Person>> helper) {
    helper.add(node); // Assume this node is a member of the list.
    if (node.getElement().equals(target)) { // If the node we're at equals the target, return it.
        return true;
    } else {
        for (MultiTreeNode<Person> child : node.getChildren()) { // For each child in the node, recurse the method.
            if (hasNodeChain(child, target, helper)) { // If a child has a path, this node is a member of the list.
                return true;
            }
        }
        // If none of the children are members, remove this node.
        helper.remove(helper.size() - 1);
        return false;
    }
}

我想我已经接近解决这个问题了,但还没有完全解决。 我刚刚添加了树中的每个元素:(。有人可以提供一些指导吗?

我无法发表评论,所以我希望这对您有所帮助。

添加节点的条件是该节点是否在您要查找的节点的路径上。

所以如果我理解正确,你可以做这样的事情(只是不是像我所做的那样的简化例子):

private ArrayList<T> findNodeChain() {
    if (findNode(node) != null) { 
        // If this node is the on the path to our node, add it to the list and return.
        helper.add(node); 
        return helper;
    } else {            
        // If none of the children have the target, 
        //there must not be a path or the node is at the end
        return helper;
      }
 }

查看本教程以了解我要解释的内容。 我实际上写出了他们拥有的 C# 代码,我认为查看 Java 示例会对您有所帮助。

要获取MultiTreeNode节点的祖先列表,您的递归调用需要将引用列表传递给自身,该列表不会由recursion where the target was foundrecursion where the target was found初始化,而是由callee that triggered the recursioncallee that triggered the recursion初始化。 见下面的片段。

 private boolean isParentOfTarget(MultiTreeNode<Person> suspect, Person target, 
  ArrayList<MultiTreeNode<Person>> chain) { 
    // Check whether the suspect is the target
    if (suspect.getElement().equals(target)) { 
       // Suspect is actually the target :|
       // No need to append to chain here!
       return true; //just head home
    } 
    else {             
       // Yet to find the target. So we check the children of the suspect
       for (MultiTreeNode<Person> child : suspect.getChildren()) {
         // The children may also have children
         // Hence we do a recursive call 
         if(isParentOfTarget(child, target, chain)){
          // Suspect is guilty :)
          chain.add(suspect); 
          return true; //head home
         } 
         // ...At this point
         // Johnny is still lost... Continue Search!
       } 
       return false; //Suspect not guilty :(
     }
 }

用法

ArrayList<MultiTreeNode<Person>> chain = new ArrayList<>();
Boolean is_pot = isParentOfTarget(root_node,target_person,chain);
if(is_pot){
 // ... A relation exist between root_node and target_person
 // Chain contains all parents of target_person excluding root_node
}
else{
 // ... Root_node and target_person exists in two different worlds
 // Chain is a blank slate
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM