Java中的基本递归算法

3

我正在尝试在Java中实现基本的RRT(快速探索随机树)算法。我有一个名为TreeNode的类,它保存节点的x和y位置,并在一个ArrayList中保存它拥有的所有子节点。在我的主程序中,我有树的根节点。如果我想在树中找到最近的邻居,我会调用这段代码。该方法以根节点作为“node”进行调用,minAbstand为Integer.MAX_VALUE。

private void NEAREST_NEIGHBOUR(int xrand, int yrand, TreeNode node, int minAbstand) {
    if((Math.sqrt(Math.pow(node.getxPos()-xrand, 2) + Math.pow(node.getyPos()-yrand, 2))) <= minAbstand){//normal method to find the distance
        minAbstand = (int) Math.sqrt(Math.pow(node.getxPos()-xrand, 2) + Math.pow(node.getyPos()-yrand, 2));
        xnearest = node;
    }
    for(int i = 0; i < node.getNodes().size(); i++){
        NEAREST_NEIGHBOUR(xrand, yrand, node.getNodes().get(i), minAbstand);
    }
}

我原以为我会通过递归遍历所有节点,并找到距离最近的一个。在使用NEAREST_NEIGHBOUR方法后,最近邻居应该被保存在xnearest中。现在我通过这种方法将新节点添加到最近节点:

xnearest.addNode(xnew)

addNode是TreeNode类的一个方法,它调用arraylist.add(node),所以只需要将节点添加到ArrayList中。之后,新节点应该是最近节点的"子节点"。然后从头开始:-创建随机节点,-找到最近的节点到随机节点,-将随机节点添加到最近的节点,......但实际上情况并非如此。

在突出显示的区域中,可以看到它没有选择距离最近的节点。我在这里做错了什么?

整个代码:

    private void doRRT(Canvas canvas, PaintEvent e, int K, int deltaT){
      for(int i = 0; i < K; i++){
          xrand = new TreeNode(new Random().nextInt(canvas.getSize().x * 2) - 500, new Random().nextInt(canvas.getSize().y * 2) - 300);

          NEAREST_NEIGHBOUR(xrand.getxPos(), xrand.getyPos(), xstart, Integer.MAX_VALUE);

          NEW_STATE(xrand.getxPos(), xrand.getyPos(), deltaT);

          e.gc.drawRectangle(xnearest.getxPos() - 1, xnearest.getyPos() - 1, 2, 2);
          e.gc.drawLine(xnearest.getxPos(), xnearest.getyPos(), xnew.getxPos(), xnew.getyPos());
      }
  }

  private void NEW_STATE(int xrand, int yrand, int deltaT) {
      int nearx = xnearest.getxPos(), neary = xnearest.getyPos();
      if(Math.sqrt(Math.pow(nearx - xrand, 2) + Math.pow(neary - yrand, 2)) > deltaT){
          float faktor = (float) (Math.sqrt(Math.pow(nearx - xrand, 2) + Math.pow(neary - yrand, 2)) / deltaT);
          xnew = new TreeNode((int) (nearx + (xrand - nearx)/ faktor), (int) (neary + (yrand - neary)/ faktor));
      } else {
          xnew = new TreeNode(xrand, yrand);
      }
      xnearest.addNode(xnew);
  }

private void NEAREST_NEIGHBOUR(int xrand, int yrand, TreeNode node, int minAbstand) {
    counter2++;
      if((Math.sqrt(Math.pow(node.getxPos()-xrand, 2) + Math.pow(node.getyPos()-yrand, 2))) < minAbstand){
          minAbstand = (int) Math.sqrt(Math.pow(node.getxPos()-xrand, 2) + Math.pow(node.getyPos()-yrand, 2));
          xnearest = node;
      }
      for(int i = 0; i < node.getNodes().size(); i++){
          NEAREST_NEIGHBOUR(xrand, yrand, node.getNodes().get(i), minAbstand);
      }
  }

还有TreeNode类:

TreeNode(int x, int y){
    xPos = x;
    yPos = y;
    nodes = new ArrayList<TreeNode>();
}

public ArrayList<TreeNode> getNodes() {
    return nodes;
}

public int getxPos() {
    return xPos;
}

public int getyPos() {
    return yPos;
}

public void addNode(TreeNode node){
    nodes.add(node);
}

解决方案?

现在这样做对吗?递归确实很棘手。

private int NEAREST_NEIGHBOUR(int xrand, int yrand, TreeNode node, int minAbstand) {
  if((Math.sqrt(Math.pow(node.getxPos()-xrand, 2) + Math.pow(node.getyPos()-yrand, 2))) < minAbstand){
      minAbstand = (int) Math.sqrt(Math.pow(node.getxPos()-xrand, 2) + Math.pow(node.getyPos()-yrand, 2));
      xnearest = node;
  }
  for(int i = 0; i < node.getNodes().size(); i++){
      minAbstand = NEAREST_NEIGHBOUR(xrand, yrand, node.getNodes().get(i), minAbstand);
  }
  return minAbstand;

}


有些不清楚:在找到比输入节点更近的节点后,您实际上要做什么?您说您将其添加到列表中,但在代码中,您却覆盖了“xnearest”变量。 - Little Santi
你发布的图是一棵树还是一个有向无环图(DAG)?如果它实际上是一棵树,那么高亮区域涵盖了两个不同的分支,我无法清楚地看出哪一个是输入节点,哪一个被假设为最近的节点在你的实验中。 - Little Santi
我在NEAREST_NEIGHBOUR中没有看到失败,但是NEW_STATE对我来说很难理解:一旦你已经有了xnearestxrand,为什么还要创建一个新节点? - Little Santi
1
我不知道你为什么认为你应该这样破坏你的问题,但不,你不应该这样做。我撤销了那个编辑,所以发布的答案不再毫无意义。 - Tom
1个回答

1
我必须纠正自己: NEAREST_NEIGHBOUR 方法有一个错误的逻辑。看:
当方法开始时,将收到的 minAbstand 与当前评估节点的距离进行比较。如果它更低,则更新 minAbstand 值以便在当前子树内递归地限制搜索标准。到目前为止,一切正常。
但是,兄弟子树呢?我的意思是:当完全浏览当前子树时,当前方法调用将结束,并因此将控制返回给调用方法,其本身则位于先前的递归框架中。但是,本地变量的值会丢失(例如 minAbstand)。
你需要的是将 minAbstand 作为 NEAREST_NEIGHBOUR 的返回值返回,并在每次递归调用时更新它。

是的!那正是我想表达的。 - Little Santi
最后一个建议:你最好提高代码的可读性,避免使用过长的表达式(尤其是重复的表达式),比如计算距离。将该计算放在一个私有方法中,并在需要的地方调用它。 - Little Santi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接