0

我在以下程序中有一个 IndexOutOfBounds 异常。它由三个文件组成:

重要的是其中只有两个,GUI 工作正常。这是第一个:

interface SudokuObserver {
    public void modified(int i, int j);
}

public class SudokuData
{
    public int[][] feld = new int[9][9];
    public SudokuObserver obs = null;

    public SudokuData()
    {
        int i,j;
        for (i=0; i<9; i++) {
            for (j=0; j<9; j++) {
                feld[i][j] = 0;
            }
        }
    }

    public int getNumber(int x, int y)
    {
        return feld[x][y];
    }

    public void setNumber(int x, int y, int v)
    {
        feld[x][y] = v;
        if (obs != null)
            obs.modified(x, y);
    }

    public void setObserver(SudokuObserver o)
    {
        obs = o;
    }

所以数独字段被分配为一个 9x9 整数数组。下面的文件称为 SudokuSolver,它有一个算法可以将每个正方形的可能数字写入 ArrayList。然后第二个算法的工作原理如下:他找到具有最小可能数字的正方形,将保存在 ArrayList 中的第一个数字设置在该正方形上并递归执行,因此他再次开始定义每个正方形的可能数字,选择可能性最少的那个,然后选择第一个将其放入该字段。执行此操作时,for 循环会遍历每个正方形的可能数字。

import java.util.*;

public class SudokuSolver
{
    SudokuData data;

    public SudokuSolver(SudokuData d)
    {
        data = d;
    }


{
  /*Pseudoalgorithm:
  - Inserts the numbers 1-9 into a Collection called res
  - Looks at line x, which numbers are in there and erases them out of the      
        collection
  - Looks at column y, which numbers are in there and erases them out of the      
        collection
  - Looks in the 3x3 Square (x,y) which numbers are already in there and erases
        them out of the collection
  - Gives back the possible candidates for that field

 */

在这里我初始化我的 ArrayList。

     public ArrayList<Integer> offen(int x, int y)
 {
 ArrayList<Integer> res = new ArrayList<Integer>(); 
         /* The collection is saved in an ArrayList */
     int k = 0;

在这里,我只是在我的 ArrayList 中填写数字 1-9。

 for (int i=1;i<10;i++) 
     {
            res.add(i);
         }

现在是困难的部分:我从零循环到九,然后循环 k。该行与给定的 x 保持一致,j 在列上运行,所以我得到了给定行中的每个正方形,并且在每个正方形中,我检查了 1-9 中的每个数字。注意:索引从 0-9 开始,而元素从 1-9 开始,因此 k 必须为 0-9,因为 get() 方法将索引作为输入。如果有任何合规性,我会从 ArrayList 中删除该元素。

   for (int j=0;j<9;j++) 
   {
     for (k=0;k<9;k++) 
     {
       if (this.data.feld[x][j] == (res.get(k)))
        res.remove(k);
     }

列、常量列和 j 循环的内容与上述相同。

     for (k=0;k<9;k++) 
     {
       if (this.data.feld[j][y] == res.get(k))
        res.remove(k);
     }
   }

现在我在两个新变量中输入了我的输入,只是因为我之前在下面输入了错误的变量名称的代码部分。

   int m = x;
   int n = y;

这是 3x3 方块的部分,我在 if 条件下执行此操作,所以这只是 9 个部分之一,我不想将它们全部发布在这里,因为它们只是在一些常数上有所不同。我检查我的输入 x,y 在哪个正方形中,然后循环遍历正方形并检查那里有哪些数字,这些数字仍然在我的 ArrayList 中并删除它们。

   if (m<=2 && n<=2) 
   {
    for (m=0;m<3;m++) 
    {
      for (n=0;n<3;n++)
      {
        for (k=0;k<9;k++)
        {
          if (this.data.feld[m][n] == res.get(k))
           res.remove(k);
        }
      }
    }
   }

现在我返回 ArrayList

  return res;
    }


//findSolution() finds a Solution
public boolean findSolution()
{
    /*Possible Strategy:
    - Find the square, which has the fewest possible candidates
      - If there are more than one candidates, who have the minimum of candidates,
            take any of them
      - If there are no more open candidates, there is a solution found. Return 
            true
    - Loop over the candidates of this square and by setting the first possible 
          candidate into this square[x][y]
    - Call the method findSolution() recursive to find in dependence of the set 
          value the values for the other fields 
      If there is a blind alley, take the next possible candidate (Backtracking!)

    */
int j = 0;
int k = 0;
int x = 0; // x coordinate of the field with the fewest open candidates
int y = 0; // y coordinate of the field with the fewest open candidates
int counter_offene_felder = 0;   // counts the number of open fields
int min = 9;   

我正在循环 j 和 k,查看可能的候选数是否超过 0,这意味着我正在遍历整个数独字段并计算开放字段的数量。

for (j=0;j<9;j++) 
   {
     for (k=0;k<9;k++) 
     {
        if ( this.offen(j,k).size() >= 0) 
        {
          counter_offene_felder += 1;
        }

如果数字小于 min = 9 个可能的候选者,我将其作为最小值并保存该字段的坐标

        if ( (this.offen(j,k)).size() < min )
        {
          x = j;
          y = k;
        }
     }
   }

现在我用尽可能少的候选者为字段初始化和 ArrayList,并使用我的 offen 方法将它们放入这个 ArrayList

  ArrayList<Integer> candidate_list = this.offen(x,y);
  for (k=0;k<this.offen(x,y).size();k++) 
  {  // runs over candidates
    int v = this.offen(x,y).get(k);   // takes the first candidate
    this.data.setNumber(x,y,v);   // writes the first candidate into square [x][y]
   this.findSolution();    // calls findSolution() recursive
  }

If there are no more open fields, I've found a solution

  if (counter_offene_felder == 0)
  {
    return true;
  }
  else return false;
}

}

问题是,我在第 39 行,索引 8 大小 8 处得到一个 IndexOutOfBounds 异常。但我不知道为什么。:(

4

2 回答 2

1

不能肯定这是你得到错误的地方......但是当你做这样的事情时你可能会遇到问题。

for (k=0;k<9;k++) 
 {
   if (this.data.feld[j][y] == res.get(k))
    res.remove(k);
 }

例如,假设在 k=1 时 if 语句的计算结果为真。然后,您将从 ArrayList 中删除一个元素。那么当 k=8 时,会抛出 IndexOutOfBounds 异常,因为 ArrayList 只包含 8 个元素(0-7)

假设没有其他线程会修改this.data.feld[][],那么在通过这个循环时你只会得到一个匹配项......所以你可以做这样的事情......

int match = -1;     

for (k=0;k<res.size();k++) {
       if (this.data.feld[j][y] == res.get(k)){
        match = k;
        break;
     }
}

if(match != -1)
     res.remove(match);
于 2013-07-03T17:44:56.143 回答
0

我认为 contains() 方法将有助于消除此循环的异常。

尝试用以下代码替换您的代码:

for (m=0;m<3;m++) 
    {
      for (n=0;n<3;n++)
      {
        if (res.contains(this.data.field[m][n]))
            res.remove(res.indexOf(this.data.field[m][n]));
      }
}

它将遍历 data.field,并检查 ArrayList 以查看它是否包含 m,n 处的值。如果是这样,它将删除它。

于 2013-07-03T18:02:43.890 回答