【问题标题】:Recursion (done)递归(完成)
【发布时间】:2014-12-11 06:18:09
【问题描述】:

我编写了这个应该可以工作的寻路算法,但是我得到了大量的 java.lang.ArrayIndexOutOfBoundsException。该程序的目标是找到从一个点到另一个点的最短路径,且成本最低。这是我的代码:

public boolean travel(int[][] path, int cX, int cY, int eX, int eY)
{
    boolean returned = false;
    System.out.println("the current X position on the GRID is: "+cX+"the current y position on the GRID is: "+cY);
    path[cX][cY]=1;
    if(cost>lowestCost - grid[cX][cY]){ 
        return false;
    }
    cost += grid[cX][cY];
    if(cX>=eX && cY>=eY){
        return true;
    }
    if(cX+1>=eX && cY+1<eY){
        return false;
    }
    if(cY+1>=eY && cX+1<eX){
        return false;
    }
    if(travel(path,cX+1,cY+1,eX,eY)==true){
        returned=true;
        replace(newBest, path);
    }
    if(travel(path,cX,cY+1,eX,eY)==true){
        returned=true;
        replace(newBest, path);
    }
    if(travel(path,cX+1,cY,eX,eY)==true){
        returned=true;
        replace(newBest, path);
    }


    return(returned);

}

cX 是数组中的当前 X 位置,cY 是数组中的当前 Y 位置,eX 和 eY 是目标坐标。 path[][] 是用来存储路径的数组。如果您有任何答案,请告诉我!也不建议任何其他算法,只是对实际代码进行一些编辑。 grid[][] 是存储从一个到另一个的成本的数组。非常感谢

 if(travel(newBest,0,0,rows,columns)==true)
                {
                    lowestCost=cost;
                }

这就是我调用该方法来查找最短路径的方式。

这是整个小程序:

import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class GridWorld extends Applet implements Runnable, MouseListener, KeyListener,     MouseMotionListener
{
public int worldx;
public int worldy;
public int columns;
public int rows;
public int destX, destY;
public int cost, lowestCost;
public boolean sizeD;
public int[][] grid;

public int[][] prevBest;

public int[][] newBest;


Graphics bufferGraphics; //Set up double buffer
Image offscreen;
Thread thread;//Sets up a Thread called thread

public void init()
{
    worldx=1000;
    worldy=1000;
    cost=0;
    lowestCost=5000;
    sizeD=false;
    columns=5;
    rows=5;
    destX=0;
    destY=0;
    grid= new int[rows][columns];
    prevBest= new int[rows][columns];
    newBest = new int[rows][columns];



    offscreen = createImage(worldx,worldy); //create a new image that's the size of the applet DOUBLE BUFFER SET UP
    bufferGraphics = offscreen.getGraphics(); //set bufferGraphics to the graphics of the offscreen image. DOUBLE BUFFER SET UP

    addKeyListener(this);//setup all the listeners
    addMouseListener(this);//setup all the listeners
    addMouseMotionListener(this);//setup all the listeners
    thread = new Thread(this);  //constructs a new thread
    thread.start();             //starts the thread
}//init()
public void fillGrid()
{
    prevBest= new int[rows][columns];
    newBest = new int[rows][columns];
    lowestCost = 0;
    for(int ro = 0;ro<rows;ro++)
    {
        for(int col = 0;col<columns;col++)
        {
                grid[ro][col]=(int)(Math.random()*100);
                newBest[ro][col]=0;
                prevBest[ro][col]=0;
                if(ro==col)
                {
                    prevBest[ro][col]=1;
                    lowestCost+=grid[ro][col];


                }
        }
    }

    destX=(rows-1);
    destY=(columns-1);
}
public boolean baseCase(int ct, int lowct, int destR, int destC, int cX, int cY)
{
    boolean returned=false;
    if(ct>=lowct)
    {
        returned=true;
    }
    if(cX+1==rows)
    {
        returned=true;
    }
    if(cY+1==columns)
    {
        returned=true;
    }
    if(cX==destR && cY==destC)
    {
        returned=true;
    }

    return(returned);
}
public boolean isValid(int x, int y, int[][] path, int eX, int eY) {
    //not valid if: cordinates are into grid dimensions
   if (!((x >= 0 && x < grid.length) && (y >= 0 && y < grid.length)))
       return false;
   //valid if: not visited yet, or is destiny
   if (path[x][y] == 0 || (x == eX && y == eY))
       return true;

   return true;
}
/*public int traverse(int steps, int destR, int destC, int curX, int curY)
{
    int direction = 0;
    if(cost>=lowestCost)
    {
        //System.out.println("Greater cost Base Case");
        direction=4;
    }
    if(curX+1>=destR && curY+1<destC)
    {
        System.out.println("Reached the farthest row Base Case");
        direction=1;
    }
    if(curY+1>=destC && curY+1<destR)
    {
        System.out.println("Reached the farthest columns Base Case");
        direction=2;
    }
    if(curX+1>=destR && curY+1>=destC)
    {
        System.out.println("At destination Base Case");
        direction=4;    
    }
    switch(direction)
    {
        case 0: newBest[curX][curY]=1;
                cost+=grid[curX][curY];
                System.out.println("the current X position on the GRID is: "+curX+"the current y position on the GRID is: "+curY);
                return(traverse(steps+1,destR,destC,curX+1,curY+1)); //diag

        case 1: newBest[curX][curY]=1;
                cost+=grid[curX][curY];
                return(traverse(steps+1,destR,destC,curX,curY+1)); //right

        case 2: newBest[curX][curY]=1;
                cost+=grid[curX][curY];
                return(traverse(steps+1,destR,destC,curX+1,curY));//down

        case 3: 
                return(5000);

        case 4: System.out.println("the Grid's cost is: "+cost);
                return(cost);
        default: return(0);

    }
}*/

 public int[][] replace(int[][] p1, int[][] p2)
 {
    for(int col=0;col<columns;col++)
        {
            for(int ro=0;ro<rows;ro++)
            {
                p1[ro][col]=p2[ro][col];
            }
        }
    return(p1);
 }
public boolean travel(int[][] path, int cX, int cY, int eX, int eY)
{
    boolean returned = false;
    System.out.println("cX: "+ cX+" , cY: "+ cY+", eX: "+eX+", eY: " +eY+" Path 1 length: "+path[0].length+" Path 2 length: "+path[1].length);
    path[cX][cY]=1;
    if(cost>lowestCost - grid[cX][cY]){ 
        System.out.println("1");
        return false;
    }
    cost += grid[cX][cY];

    }
    if(travel(path,cX+1,cY+1,eX,eY)==true && isValid(cX+1,cY+1,newBest,eX,eY)){
        System.out.println("the current X position on the GRID is: "+cX+"the current y position on the GRID is: "+cY);
        returned=true;
        replace(newBest, path);
    }
    if(travel(path,cX,cY+1,eX,eY)==true && isValid(cX,cY+1,newBest,eX,eY)){
        System.out.println("the current X position on the GRID is: "+cX+"the current y position on the GRID is: "+cY);

        returned=true;
        replace(newBest, path);
    }
    if(travel(path,cX+1,cY,eX,eY)==true && isValid(cX+1,cY,newBest,eX,eY)){
        System.out.println("the current X position on the GRID is: "+cX+"the current y position on the GRID is: "+cY);

        returned=true;
        replace(newBest, path);
    }


    return(returned);

}

public void paint(Graphics g) 
{// paint() is used to display things on the screen
    setSize(worldx,worldy);
    //clear the offscreen image
    bufferGraphics.clearRect(0,0,worldx,worldy);
    bufferGraphics.setColor(Color.black);
    //bufferGraphics.fillRect(0,0,worldx,worldy);

    if(sizeD==true)
    {
        if(travel(newBest,0,0,rows,columns)==true)
                {
                    lowestCost=cost;
                }
    }
    for(int ro = 0;ro<rows;ro++)
    {
        for(int col = 0;col<columns;col++)
        {
            if(sizeD==true)
            {

                if(newBest[ro][col]==1)
                {
                    bufferGraphics.setColor(Color.red);
                    bufferGraphics.fillRect((50*col),(50*ro),50,50);
                    bufferGraphics.setColor(Color.black);
                }
                if(prevBest[ro][col]==1)
                {
                    bufferGraphics.setColor(Color.gray);
                    bufferGraphics.fillRect((50*col),(50*ro),50,50);
                    bufferGraphics.setColor(Color.black);
                }

                bufferGraphics.drawLine(0,(50*ro),50*columns,(50*ro));
                bufferGraphics.drawLine((50*col),0,(50*col),50*rows);
                bufferGraphics.drawString(""+grid[ro][col],(50*ro)+25,(50*col)+25);



            }

        }
    }

    if(sizeD==false)
    {
        bufferGraphics.drawRect(200,300,100,100);
        bufferGraphics.drawString("5",250,350);
        bufferGraphics.drawRect(400,300,100,100);
        bufferGraphics.drawString("10",450,350);
        bufferGraphics.drawRect(600,300,100,100);
        bufferGraphics.drawString("20",650,350);
    }


    g.drawImage(offscreen,0,0,worldx,worldy,this);//Draw the screen
}// paint()

public void mouseDragged(MouseEvent e) {

}
public void mouseMoved(MouseEvent e){

}
public void mousePressed(MouseEvent e) 
{

}
public void mouseReleased(MouseEvent e) 
{

}
public void mouseEntered(MouseEvent e) 
{
   System.out.println("Mouse entered");
}
public void mouseExited(MouseEvent e) 
{
   System.out.println("Mouse exited");
}
public void mouseClicked(MouseEvent e) 
{
   System.out.println("Mouse clicked (# of clicks: "+ e.getClickCount() + ")");
   int mX=e.getX();
   int mY=e.getY();
   if(new Rectangle(200,300,100,100).contains(mX,mY) && sizeD==false)
   {
    columns=5;
    rows=5;
    grid= new int[rows][columns];
    fillGrid();
    sizeD=true;
   }
   if(new Rectangle(400,300,100,100).contains(mX,mY) && sizeD==false)
   {
    columns=10;
    rows=10;
    grid= new int[rows][columns];
    fillGrid();
    sizeD=true;

   }
   if(new Rectangle(600,300,100,100).contains(mX,mY) && sizeD==false)
   {
    columns=20;
    rows=20;
    grid= new int[rows][columns];
    fillGrid();
    sizeD=true;
   }

}
public void keyPressed( KeyEvent event ) 
{
    String keyin; // define a non‐public variable to hold the string representing the key input
    keyin = ""+event.getKeyText( event.getKeyCode()); 
    System.out.println("Key pressed "+keyin);
}//keyPressed()
public void keyReleased( KeyEvent event ) 
{
    String keyin;
    keyin = ""+event.getKeyText( event.getKeyCode()); 
    System.out.println ("Key released: "+ keyin);
}//keyReleased()
public void keyTyped( KeyEvent event ) 
{
 char keyin;
keyin = event.getKeyChar(); //getKeyChar() returns the character of the printable key pressed. 
System.out.println ("Key Typed: "+ keyin);
}//keyTyped()
public void update (Graphics g) 
{
    paint(g); 
}//Update the graphics

public void run() 
{
    while(true) // this thread loop forever and runs the paint method and then sleeps.
    {

        repaint();
        try {
        thread.sleep(50);
        }
        catch (Exception e){ }
    }//while
}// run()

}//小程序

【问题讨论】:

  • 您所说的“grid[][] 是存储从一个到另一个的成本的数组。” ?
  • grid [] [] 是存储网格中每个图块成本的多维数组

标签: java arrays algorithm recursion


【解决方案1】:

你得到了大量的java.lang.ArrayIndexOutOfBoundsException,因为你没有正确管理进入最后三个 if 块的流程。代码将进入最后三个 if 块,因为即使您设置了边界检查(前两个 if 块),您也只返回 return(returned); 的状态。所以,path[cX][cY]grid[cX][cY] 在cX 和cY 较大的情况下可能会遇到索引越界(取决于路径和网格的索引设置)。

另外,前四个 if 块的检查逻辑顺序不正确,当条件满足时你应该返回状态。

前四个 if 块应重新排列为:

if(cost>=lowestCost){ 
    return false;
}
if(cX==eX && cY==eY){
    return true;
}
if(cX+1>=eX && cY+1<eY){
    return false;
}
if(cY+1>=eY && cX+1<eX){
    return false;
}

顺便说一句,请确保您的边界检查(cX+1&gt;=eX &amp;&amp; cY+1&lt;eYcY+1&gt;=eY &amp;&amp; cX+1&lt;eX)是正确的。这会使代码无法访问([eX-1,eX],[0,eY-2])([0,eX-2],[eY-1,eY]) 中的点。

还有一点,您可能会遇到cost&gt;=lowestCost 的麻烦,因为在极少数情况下,例如所有可能的最短路径的成本都等于预设的最低成本值。处理此问题的一种方法是删除等号。

再一次,对于像cost = Integer.MAX_VALUE + 1 这样的极端情况,您可能会遇到cost&gt;=lowestCost 的麻烦。要解决这个问题,您可以尝试

if(cost>lowestCost - grid[cX][cY]){ 
    return false;
}
cost += grid[cX][cY];

【讨论】:

  • 感谢 hkg279,解决了很多问题,但我仍然遇到更多代码问题,它现在只有线程“AWT-EventQueue-1”中的一个异常 java.lang.ArrayIndexOutOfBoundsException: 20 .任何想法如何解决?我更新了原帖中的代码
【解决方案2】:

这是一个带有回溯的递归解决方案,代码解释:

public class FindShortestPath {

    //the map is represented as a graph, and the graph is represented as an adyacent matrix
    int map[][] = {{-1, 1, 1, 20},    //-1 = there is no edge between two vertexs
                  {-1, -1, 3, 1},
                  {-1, -1, -1, 1},
                  {-1, -1, -1, -1}};
    
    int distSol = Integer.MAX_VALUE;                    //we want to minimize this value
    List<Integer> solution = new ArrayList<Integer>();  //path solution

    public static void main(String[] args) {
        new FindShortestPath().start();
    }

    void start() {
        /* In this case we find shortest path from 0 to 3 */
        findShortestPath(new boolean[map.length], 0, 3, 0, new ArrayList<Integer>());
        
        System.out.println("Distance: " + distSol);
        System.out.println(solution.toString());
    }

    /**
     * 
     * @param visit   auxiliary array to mark visited
     * @param c       actual vertex
     * @param destiny destiny vertex
     * @param distAct actual distance traveled
     * @param path    actual path traveled
     */
    void findShortestPath(boolean visit[], int c, int destiny, int distAct, List<Integer> path) {
        if (c == destiny) {                             //base case: we reach destiny
            if (distAct <= distSol) {                   //check if actual distance is better than solution                
                distSol = distAct;
                solution = new ArrayList<Integer>(path);   //replace old solution
                solution.add(destiny);
            }
        } else {                                        //recursive case
            path.add(c);                                //add actual vertex as a possible candidate into actual path
            visit[c] = true;

            for (int i = 0; i < map.length; i++) {      //visit every adyacent vertex that was no visited yet
                if (map[c][i] != -1 && !visit[i]) {
                    findShortestPath(visit, i, destiny, distAct + map[c][i], path);
                }
            }

            path.remove(path.size() - 1);               //remove this vertex from the path
            visit[c] = false;
        }
    }
}

此示例的输出:

距离:2

[0, 2, 3]

编辑

OP 希望地图是一个网格:

public class FindShortestPath2 {

    int lowestCost = Integer.MAX_VALUE;
    
    int grid[][] = {{0, 9, 0, 0},  
                   { 0, 5, 1, 1},
                   { 0, 0, 2, 0},
                   { 0, 0, 0, 0}};
    
    int sol[][] = new int[4][4];      //this is the path solution
    
    public static void main(String[] args) {
        new FindShortestPath2().start();
    }

    void start() {
        travel(new int[4][4], 0, 0, 2, 2, 0);
        System.out.println("Lowest cost: " + lowestCost);
        printPath(sol);  //print solution
    }

    public void travel(int[][] path, int cX, int cY, int eX, int eY, int cost) {
        if (cX == eX && cY == eY) {    //reach destiny cordinates
            if (cost < lowestCost) {
                lowestCost = cost;
                path[cX][cY] = 1;
                replace(sol, path);             
            }
        } else {
            path[cX][cY] = 1;         //mark path
            
            if (isValid(cX + 1, cY + 1, path, eX, eY)) {    //move in diagonal (rigth-down)       
                travel(path, cX + 1, cY + 1, eX, eY, cost + grid[cX + 1][cY+1]);
            }
            if (isValid(cX, cY + 1, path, eX, eY)) {        //move rigth
                travel(path, cX, cY + 1, eX, eY, cost + grid[cX][cY+1]);
            }
            if (isValid(cX + 1, cY, path, eX, eY)) {        //move down
                travel(path, cX + 1, cY, eX, eY, cost + grid[cX + 1][cY]);
            }

            path[cX][cY] = 0;       //unmark path
        }
    }

    
    boolean isValid(int x, int y, int[][] path, int eX, int eY) {
        //not valid if: cordinates are into grid dimensions
       if (!((x >= 0 && x < grid.length) && (y >= 0 && y < grid.length)))
           return false;
       
       //valid if: not visited yet, or is destiny
       if (path[x][y] == 0 || (x == eX && y == eY))
           return true;
       
       return true;
    }
    
    void replace(int[][] p1, int[][] p2) {
        for (int col = 0; col < p1.length; col++) {
            for (int ro = 0; ro < p1.length; ro++) {
                p1[ro][col] = p2[ro][col];
            }
        }
    }
    
    void printPath(int[][] p) {
        for (int col = 0; col < p.length; col++) {
            for (int ro = 0; ro < p.length; ro++) {
                System.out.print(p[col][ro] + " ");
            }
            System.out.println();
        }
        System.out.println();
    }
}

此示例的输出:

Lowest cost: 2

1 0 0 0 
1 0 0 0 
0 1 1 0 
0 0 0 0 

【讨论】:

  • 嘿,谢谢您的回复,但正如我所提到的,只是对代码进行了一些编辑,实现新代码只是一种廉价的编码而且很困难,因为我的很多变量不适合该算法.
  • @JacobAronoff 发布您的输入网格。
  • 这是一个随机生成的网格,大小为 5×5、10×10 或 20×20。
  • @JacobAronoff 在什么坐标 x,你开始搜索?而costlowestCost的初始值是多少?
  • 我从 5000 开始(只是一个大数字),然后在 fillGrid() 中将其重置为 0,然后添加到它。我从坐标(0,0)开始
【解决方案3】:

这可能是题外话,但您是否尝试过在 Java 中实现 Dijkstra 算法。在以下算法中,代码 u := vertex in Q with min dist[u] 搜索顶点集 Q 中具有最小 dist[u] 值的顶点 u。 length(u, v) 返回连接两个相邻节点 u 和 v 的边的长度(即之间的距离)。第 17 行的变量 alt 是从根节点到相邻节点 v 的路径长度,如果它要经过你。如果此路径短于为 v 记录的当前最短路径,则当前路径将替换为此 alt 路径。前一个数组填充了指向源图上“下一跳”节点的指针,以获得到源的最短路径。 (取自维基百科关于 Dijkstra 算法的文章。这项工作不是我自己的。

function Dijkstra(Graph, source):
  dist[source]  := 0                     // Distance from source to source
  for each vertex v in Graph:            // Initializations
      if v ≠ source
          dist[v]  := infinity           // Unknown distance function from source to v
          previous[v]  := undefined      // Previous node in optimal path from source
      end if 
      add v to Q                         // All nodes initially in Q (unvisited nodes)
  end for

  while Q is not empty:                  // The main loop
      u := vertex in Q with min dist[u]  // Source node in first case
      remove u from Q 

      for each neighbor v of u:           // where v has not yet been removed from Q.
          alt := dist[u] + length(u, v)
          if alt < dist[v]:               // A shorter path to v has been found
              dist[v]  := alt 
              previous[v]  := u 
          end if
      end for
  end while
  return dist[], previous[]
 end function

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-13
    • 2017-06-22
    • 2018-11-26
    • 1970-01-01
    • 2018-02-21
    • 2021-11-11
    • 2016-03-18
    • 2012-10-27
    相关资源
    最近更新 更多