【问题标题】:How to get recursion and for loop work together in Java?如何在 Java 中让递归和 for 循环一起工作?
【发布时间】:2011-03-08 19:47:16
【问题描述】:

我需要递归地创建一个树结构。在树中,每个节点都有不同数量的子节点,所以我认为我需要在 for 循环中递归调用该方法。 for 循环的循环次数与当前节点有多少子节点一样多。

该函数首先在深度 d 中创建最左边的孩子,然后返回(或应该返回)到前一个深度并创建另一个,依此类推。我相信你知道我在这里的意思。所以我试图以这种方式创建整个树。我已经设置了一个基本情况,以便如果满足基本情况的条件,则不再递归调用该方法。问题是我的程序以某种方式设法克服了这些条件并继续递归调用该方法,尽管它不应该这样做。

代码如下:

    private void makeTree(GameState prevState, Vector moves, Node parentNode, int index, int depthLimit) {

    if(prevState.getPossibleMoveCount(index) != 0){

        for(int i = 0; i < moves.size(); i++){

            Move thisMove = (Move)moves.get(i);
            GameState newState = prevState.getNewInstance(thisMove);
            Node child = new Node(newState, thisMove);
            parentNode.addChild(child);
            child.setParent(parentNode);

            if((child.getDepth() + 1) < depthLimit){

                int newIndex = switchIndex(index);
                Vector newMoves = newState.getPossibleMoves(newIndex);
                makeTree(newState, newMoves, child, newIndex, depthLimit);

            }else{

                child.setScore(newState.getMarkCount(index));
            }
        }
    }
}

这里的 Node 类不是 Java 默认的 Node 类,而是属于这个接口的一个类。我知道不应该创建一个与某个默认 Java 类具有相同名称的类,但这个接口不是我的。我只需要实现它。 Node 类不会与 Java Node 类发生冲突。所以我认为这不会造成任何问题。

真正的问题是 if((child.getDepth() + 1) 似乎对程序没有任何影响。程序每次都继续递归调用该方法,直到它到达深度 61,此时内存耗尽。深度限制设置为 5,但就像我说的,这似乎无关紧要。

关键是当程序处于深度“depthLimit -1”时,它应该停止递归调用,而是为当前节点的子节点设置分数,然后继续执行所有这些操作恰好是下一个元素的事情。因为这个方法不返回任何东西(void 方法),所以不需要任何返回调用,对吧?

我希望你明白我想要做什么以及出了什么问题。任何帮助表示赞赏。如果您需要更多信息,请尽管询问,我会尝试更仔细地解释这一点。

提前致谢。

E:方法中的 depthLimit 参数在第一次调用之前给出,并且在树创建期间不会更改。

【问题讨论】:

  • 你试过用调试器运行它,看看为什么会出错吗?另外,如果是家庭作业,请用 homework 标记它
  • 循环中似乎没有任何地方为孩子分配深度,大概是 child.getDepth() 总是返回 0?
  • 你是否在某处增加了节点的深度?
  • 接口文档说Node会自动跟踪深度。它没有说明节点是如何做到这一点的,但在实际代码中我有一些调试打印打印节点的深度,它似乎工作。
  • 我不知道有一个 Java 默认 Node 类 ...您的意思是接口javax.xml.soap.Nodeorg.w3c.dom.Node 之一吗?只要您不在同一个程序中使用这些 API,就不必担心,Node 是一个过于笼统的名称,无法保留给 XML 处理 API。

标签: java recursion for-loop


【解决方案1】:

您的问题不在您发布的部分。

我为您方法中使用的所有类和方法添加了虚拟实现,它运行得很好,在第 6 级停止。

package de.fencing_game.paul.examples;

import java.util.*;

public class RecursionAndLoop {


    private static class Move {
        private String id;
        public Move(String type) {
            this.id = type;
        }
        public String toString(){
            return "Move(" + id + ")";
        }

    }


    private static class GameState {
        private static int nextID;

        private int id;

        GameState() {
            this.id = nextID++;
        }

        public GameState getNewInstance(Move move) {
            return new GameState();
        }

        public int getPossibleMoveCount(int index) {
            return 5;
        }

        public Vector<Move> getPossibleMoves(int index) {
            Vector<Move> v = new Vector<Move>();
            for(int i = 0; i < 5; i++) {
                v.add(new Move(index + "×" + i));
            }
            return v;
        }

        public int getMarkCount(int index) {
            return 20 + index;
        }

        public String toString() {
            return "GameState[" + id + "]";
        }
    }

    private static class Node {
        private GameState state;
        private Move move;

        private List<Node> children;
        private Node parent;
        private int score;

        public Node(GameState s, Move m) {
            this.children = new ArrayList<Node>();
            this.state = s;
            this.move = m;
        }

        public void addChild(Node child) {
            children.add(child);
        }

        public void setParent(Node node) {
            parent = node;
        }

        public void setScore(int neu) {
            this.score = neu;
        }

        public int getDepth() {
            if(parent == null) {
                return 0;
            }
            return 1 + parent.getDepth();
        }

        /**
         * prints a simple tree view of this ZipNode and its descendants
         * on {@link System.out}.
         * @param prefix a prefix string to add before all lines.
         * @param self a prefix string to add before the line of this node
         *    itself (after the general prefix).
         * @param sub a prefix string to add before the line of all subnodes
         *    of this node (after the general prefix).
         */
        private void printTree(String prefix,
                               String self,
                               String sub) {
            System.out.println(prefix + self + state + " - " + move +
                               " - " + score);
            String subPrefix = prefix + sub;
            // the prefix strings for the next level.
            String nextSelf = " ├─ ";
            String nextSub =  " │ ";
            Iterator<Node> iterator =
                this.children.iterator();
            while(iterator.hasNext()) {
                Node child = iterator.next();
                if(!iterator.hasNext() ) {
                    // last item, without the "|"
                    nextSelf = " └─ ";
                    nextSub =  "   ";
                }
                child.printTree(subPrefix, nextSelf, nextSub);
            }
        }



    }


    int switchIndex(int index) {
        return index + 1;
    }



    private void makeTree(GameState prevState, Vector<Move> moves, Node parentNode, int index, int depthLimit) {

        if(prevState.getPossibleMoveCount(index) != 0){

            for(int i = 0; i < moves.size(); i++){

                Move thisMove = moves.get(i);
                GameState newState = prevState.getNewInstance(thisMove);
                Node child = new Node(newState, thisMove);
                parentNode.addChild(child);
                child.setParent(parentNode);

                if((child.getDepth() + 1) < depthLimit){

                    int newIndex = switchIndex(index);
                    Vector<Move> newMoves = newState.getPossibleMoves(newIndex);
                    makeTree(newState, newMoves, child, newIndex, depthLimit);

                }else{

                    child.setScore(newState.getMarkCount(index));
                }
            }
        }
    }


    public static void main(String[] params) {
        GameState start = new GameState();
        Vector<Move> m = new Vector<Move>();
        m.add(new Move("start"));
        Node root = new Node(start, null);
        int index = 7;
        int depthLimit = 6;
        new RecursionAndLoop().makeTree(start, m, root, index, depthLimit);
        root.printTree("", " ", "");
    }

}

(我对泛型类型进行了一些更改以避免编译器警告。)

这是 depthLimit=4 的输出:

GameState[0] - null - 0
└─ GameState[1] - Move(start) - 0
   ├─ GameState[2] - Move(8×0) - 0
   │  ├─ GameState[3] - Move(9×0) - 29
   │  ├─ GameState[4] - Move(9×1) - 29
   │  ├─ GameState[5] - Move(9×2) - 29
   │  ├─ GameState[6] - Move(9×3) - 29
   │  └─ GameState[7] - Move(9×4) - 29
   ├─ GameState[8] - Move(8×1) - 0
   │  ├─ GameState[9] - Move(9×0) - 29
   │  ├─ GameState[10] - Move(9×1) - 29
   │  ├─ GameState[11] - Move(9×2) - 29
   │  ├─ GameState[12] - Move(9×3) - 29
   │  └─ GameState[13] - Move(9×4) - 29
   ├─ GameState[14] - Move(8×2) - 0
   │  ├─ GameState[15] - Move(9×0) - 29
   │  ├─ GameState[16] - Move(9×1) - 29
   │  ├─ GameState[17] - Move(9×2) - 29
   │  ├─ GameState[18] - Move(9×3) - 29
   │  └─ GameState[19] - Move(9×4) - 29
   ├─ GameState[20] - Move(8×3) - 0
   │  ├─ GameState[21] - Move(9×0) - 29
   │  ├─ GameState[22] - Move(9×1) - 29
   │  ├─ GameState[23] - Move(9×2) - 29
   │  ├─ GameState[24] - Move(9×3) - 29
   │  └─ GameState[25] - Move(9×4) - 29
   └─ GameState[26] - Move(8×4) - 0
      ├─ GameState[27] - Move(9×0) - 29
      ├─ GameState[28] - Move(9×1) - 29
      ├─ GameState[29] - Move(9×2) - 29
      ├─ GameState[30] - Move(9×3) - 29
      └─ GameState[31] - Move(9×4) - 29

【讨论】:

  • 感谢您非常清晰和深入的回答。我认为递归函数正在犯一些奇怪的错误,但也许问题出在其他地方。我想知道它可能在哪里。现在进行更多调试。
  • 浏览了我所有的问题,发现这个问题没有被接受的答案。我将此答案标记为已接受,因为当时此答案引导我走向正确的方向。
【解决方案2】:

当你打电话时

makeTree(newState, newMoves, child, newIndex, depth);

在您的 if 语句中,您期望深度来自哪里?看起来您正在将深度传递给 makeTree 例程,但期望它是当前节点的深度(可能是 this.depth?)

【讨论】:

  • 对不起,我忘了在问题中提到深度参数是深度限制。它在第一次调用期间在方法中传递,并且在树创建期间保持不变。
猜你喜欢
  • 2018-01-23
  • 2013-02-17
  • 2011-06-15
  • 1970-01-01
  • 2022-01-15
  • 2022-06-25
  • 1970-01-01
  • 2016-02-06
  • 2016-07-18
相关资源
最近更新 更多