簡體   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