【问题标题】:Java populating a 3D linked list with recursionJava 使用递归填充 3D 链表
【发布时间】:2016-01-04 10:13:50
【问题描述】:

我在尝试填充我的 3D 链接列表时遇到堆栈溢出。我不明白为什么它没有在指定的范围内停止,它只是永远运行。这可能是一个简单的错误,我只是不明白。

编辑:好的,我现在已经更新了代码并删除了那个愚蠢的错误,但是它仍然没有完全按预期运行。它似乎确实在生成 10x10x10 列表,但是它无限运行。用 (10, 10, 10) 初始化,它应该创建 10000 个对象并停止。我只是想创建一个列表来表示一个 3d 坐标平面,每个整数坐标是一个节点,可以通过方向指针北、南、东、西、上或下访问。

任何帮助表示赞赏

public class Main {


    public static void main(String[] args) {
        NodeController3D con = new NodeController3D(6,6, 6);

    }

}
public class Node3D {

//    public Node3D(Node3D... nodes) {
//        if (nodes.length != 5) {
//            throw new RuntimeException();
//        }
//        this.nodes = nodes;
//    }

    public Node3D[] nodes;
    public int x, y, z;


    public Node3D north() {
        return nodes[0];
    }

    public Node3D south() {
        return nodes[1];
    }

    public Node3D east() {
        return nodes[2];
    }

    public Node3D west() {
        return nodes[3];
    }

    public Node3D up() {
        return nodes[4];
    }

    public Node3D down() {
        return nodes[5];
    }
}

public class NodeController3D {

    public NodeController3D(int length, int width, int height) {
        HEAD = new Node3D();
        pnc(HEAD, length, width, height);
    }

    private void pnc(Node3D node, int xMax, int yMax, int zMax) {
        if(node.nodes == null) {
            node.nodes = new Node3D[5];
        }

        if (node.x < xMax) {
            Node3D newNode = node.nodes[2] = new Node3D();
            newNode.x = node.x + 1;
            newNode.y = node.y;
            newNode.z = node.z;
            System.out.println(newNode.x + ", " + newNode.y + ", " + newNode.z);

            pnc(newNode, xMax, yMax, zMax);
        }
        if (node.y < yMax) {
            Node3D newNode = node.nodes[0] = new Node3D();
            newNode.x = node.x;
            newNode.y = node.y + 1;
            newNode.z = node.z;

            pnc(newNode, xMax, yMax, zMax);
        }
        if (node.z < zMax) {
            Node3D newNode = node.nodes[4] = new Node3D();
            newNode.x = node.x;
            newNode.y = node.y;
            newNode.z = node.z + 1;

            pnc(newNode, xMax, yMax, zMax);
        }
    }

//    public NodeController3D(int radius) {
//
//    }

    public final Node3D HEAD;
}

编辑:好的,我现在已经更新了代码并删除了那个愚蠢的错误,但是它仍然没有完全按预期运行。它似乎确实在生成 10x10x10 列表,但是它无限运行。用 (10, 10, 10) 初始化,它应该创建 10000 个对象并停止。我只是想创建一个列表来表示 3d 坐标平面,每个整数坐标都是一个节点,可以通过方向指针访问。

【问题讨论】:

  • 粘贴您的堆栈跟踪。
  • 已更新。它重复了这两行
  • 由于移除包装,行号不对应,我将行号添加到违规行的代码中

标签: java list recursion nodelist


【解决方案1】:

您遇到了无限递归。

所以发生了什么。

您正在创建一个新的Array

if(node.nodes == null) {
   node.nodes = new Node3D[5];
}

您继续使用Node3D 作为newNode 变量。发生这种情况是因为 node.x&lt;xMax 将是真的。 ->Node3D newNode = node.nodes[2] = new Node3D();

你现在递归调用pnc,使用这个newNode

那么现在会发生什么,node.y&lt;yMax 将是 true 。 现在您重新分配新节点。 Node3D newNode = node.nodes[0] = new Node3D();。 并再次递归调用pnc。但是你现在遇到了问题。因为它是一个新的Node3D,所以您的node.x&lt;xMax 将再次为真,这两个步骤将再次发生并无限期直到您收到您提到的错误。

要修复此错误,您可能需要将 node.xnode.y 复制到新创建的变量中。

通过改变赋值,你可以跳出无限递归。

if (node.x < xMax) {
    if (node.nodes[2] == null) {
        node.nodes[2] = new Node3D();
    }
    Node3D newNode = node.nodes[2];
    newNode.x = node.x + 1;
    newNode.y = node.y;
    newNode.z = node.z;

    pnc(newNode, xMax, yMax, zMax);
}
if (node.y < yMax) {
    if (node.nodes[0] == null) {
        node.nodes[0] = new Node3D();
    }
    Node3D newNode = node.nodes[0];
    newNode.x = node.x;
    newNode.y = node.y + 1;
    newNode.z = node.z;

    pnc(newNode, xMax, yMax, zMax);
}
if (node.z < zMax) {
    if (node.nodes[4] == null) {
        node.nodes[4] = new Node3D();
    }
    Node3D newNode = node.nodes[4];
    newNode.x = node.x;
    newNode.y = node.y;
    newNode.z = node.z + 1;

    pnc(newNode, xMax, yMax, zMax);
}

但是由于我不知道您在数组中的这些特定索引处尝试使用这些特定元素来实现什么,这对您来说可能是一个错误的解决方案。

【讨论】:

  • 感谢您帮助我修复了部分问题,但请查看更新后的问题 :)
【解决方案2】:

每当您创建一个新的 Node3D 时,变量 x、y 和 z 都不会被初始化,因此如果被访问,它们的计算结果将为 0。

在 pnc 方法中,总是存在 x

一个好的做法是尽可能将变量设为私有和最终变量:

class Node3D {
    private final Node3D[] nodes;
    private final int x;
    private final int y;
    private final int z;

    public Node3D(int x, int y, int z) {
        this.nodes = new Node3D[6];
        this.x = x;
        this.y = y;
        this.z = z;
    }
}

这将防止将来出现此类错误。您可以为变量创建 getter 方法。如果您确实需要重新分配 x、y 或 z 的值,则可以改为创建一个新的 Node3D,以便该对象可以保持不可变。

【讨论】:

  • 感谢您帮助我修复了部分问题,但请查看更新后的问题 :)
【解决方案3】:

您以多种方式导航到 3D 网格中的节点。例如,您从 (1,0,0) 和 (0,1,0) 都转到 (1,1,0),为同一坐标创建重复项。这样,您创建的节点数量等于每个节点的 cube paths 的总和。

另一种方法是填充节点立方体,并为每个节点提供对它们所在立方体的引用。然后当您需要向北移动时,只需让立方体返回正确的节点,使用的坐标当前节点。您可以使用 Apache 的 MultiKeyMap 作为网格:

class Node3D {
    private static int instances = 0;
    public final int x;
    public final int y;
    public final int z;
    public final int number;
    public final MultiKeyMap<Integer, Node3D> gridMap;

    public Node3D(MultiKeyMap<Integer, Node3D> gridMap, int x, int y, int z) {
        this.gridMap = gridMap;
        this.x = x;
        this.y = y;
        this.z = z;
        this.number = instances++;
    }

    //Add/alter these methods according to your orientation
    //Returns null if no value is present, you might want to handle this
    public Node3D getNorthNode() {
        return gridMap.get(this.x + 1, this.y, this.z);
    }

    //Other getters omitted

    @Override
    public String toString() {
        return "Node3D#" + number + "[" + x + ", " + y + ", " + z + "]";
    }
}

现在可以按如下方式进行初始化:

    MultiKeyMap<Integer, Node3D> gridMap = new MultiKeyMap<>();
    for(int x = 0; x < xMax; x++) {
        for(int y = 0; y < yMax; y++) {
            for(int z = 0; z < zMax; z++) {
                gridMap.put(x, y, z, new Node3D(gridMap, x, y, z));
            }
        }
    }

    System.out.println(gridMap.get(4, 4, 4).getNorthNode());

【讨论】:

  • 感谢您的帮助,但我一直在寻找一种方法来绕过地图中的速度限制。有没有办法让它更接近原始方式但不遵循多维数据集路径?我知道您可以使用嵌套循环轻松填充 2d 数组,为什么不能使用 3d 数组?
  • 基本上,当您以另一种方式进行操作时,您必须将每个新创建的节点注册到其所有潜在的邻居,并将每个邻居注册到新创建的节点。这将防止创建重复节点。但我认为这种方法会更加乏味且容易出错。
猜你喜欢
  • 1970-01-01
  • 2018-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多