【问题标题】:Java: 2D array of arraylists?Java:数组列表的二维数组?
【发布时间】:2013-08-27 03:20:20
【问题描述】:

我正在开发一个数独求解程序,我需要一个数组列表来保存 9x9 板上每个方块的数字 1 到 9。这些数组列表中的每一个都对应于可以进入该方格的可能数字,如果一个数字不能进入该方格,则将其从列表中删除。

我希望能够拉出它正在处理的当前方格的数组列表,例如,如果我想从对应于方格 (3,5) 的数组列表中删除数字 7

arrayOfLists[3][5].remove(Integer.valueOf(7));

但是我不知道该怎么做。当我尝试创建数组时,我在声明我的数组列表的行中收到此错误

无法创建 ArrayList 的泛型数组

这是我的代码:

    //create arraylist
    ArrayList<Integer> nums = new ArrayList<Integer>();

    //fill arraylist with numbers 1-9
    for (int i = 1; i < 10; i++) {
        nums.add(i);
    }

    //create 9x9 array of arraylists
    ArrayList<Integer>[][] array = new ArrayList<Integer>[9][9];

    //fill each element of array with arraylist of numbers 1-9
    for(int i = 0; i<9; i++){
        for(int j = 0; j<9; j++){
            array[i][j] = nums;
        }       
    }

}

是我做错了还是无法创建数组列表?如果不可能,那我该怎么做呢?

【问题讨论】:

  • 将第 10 个元素 ArrayList&lt;Integer&gt; 替换为 boolean[9] 并将那些被移除的元素设置为 false
  • 我在这些链接的任何答案中都没有看到这一点,但我只是尝试了private class IntegerArrayList extends ArrayList&lt;Integer&gt; { ... } 并声明了刚刚使用super(...) 的ArrayList 之类的构造函数;然后我能够使用new IntegerArrayList[9][9]ArrayList 方法在数组组件上运行良好,例如a[i][j].add(n)。这种方法行不通有什么原因吗?
  • 我会使用数组,而不是 ArrayList。

标签: java arrays arraylist


【解决方案1】:

每当我看到列表列表时,警钟就会开始响起。您真正想要这种东西的情况确实很少见,而这不是其中之一。

你有一个固定的棋盘,由 9 个固定的方格、列和行组成,每个位置可能有 1-9 的数字。

对所有这些概念都使用数组,因为它们的大小是固定的,并且您需要直接访问每个元素 - 集合没有任何好处,反而会成为障碍。使用逻辑(可能是集合)确保数字在每个区域中只使用一次。

【讨论】:

  • 你为什么一直说'if'而不是'of'?
  • @Zoltán 是的,我似乎经常这样做。这是因为我几乎只使用我的 iPhone 发帖,而且我的右手拇指经常没有向后弯曲到足以击中“o”而改为击中“I”。再加上我的视力很差,我没有注意到错误。你问! :)
【解决方案2】:

使用位域而不是数组列表。也就是说,使用一个整数,其中 1-9 位表示数字的可能性。测试、添加、删除单个数字是 O(1),并且它具有固定的内存大小。将整数封装在它自己的知道操作的对象中。

【讨论】:

  • 此外,对于这种特殊用途,该程序似乎可能希望同时测试多个数字。 (我从未尝试编写数独求解器,这只是基于我自己求解它们时所经历的思考过程。)为此,使用整数的位可能会导致更简单的代码。封装整数的好主意。
【解决方案3】:

一些事情:

1) 在你的 for 循环中,array[i][j] = nums;这将在数​​组的每个元素中产生相同的对象。如果您在数组的一个元素上调用 remove(),它将影响所有其他元素。您想为每个元素构建一个单独的列表对象。

2) 程序到接口;将 nums 声明为 List 而不是 ArrayList。

3) 使用列表列表,而不是任何列表数组。

    List<List<List<Integer>>> list = new ArrayList<List<List<Integer>>>();
    for(int i = 0; i<9; i++){
        List<List<Integer>> row = new ArrayList<List<Integer>>();
        for(int j = 0; j<9; j++){
            List<Integer> nums = new ArrayList<Integer>();
            for (int k = 1; k < 10; k++) {
                nums.add(i);
            }
            row.add(nums);
        }
        list.add(row);
    }

    // You can still get an element by index
    int x = list.get(3).get(1).remove(6);

但这有点笨拙。您可能需要考虑编写一个代表板的类。这样你至少会有更好地抽象它的操作。

【讨论】:

    【解决方案4】:

    您可以完全删除使用 2d 的东西并保留一个列表,方法是为每个方块指定一个 1...81 的唯一数字。因此,如果您正在使用 3,5 单元格,这意味着它是列表中的 9*2+5 = 23rd 项目。这将大大简化列表操作。给定 (3,5) 类型的参考,您可以使用单一方法给出唯一的单元格索引

    【讨论】:

      【解决方案5】:

      好的,我将把这个作为答案发布,因为它似乎对我有用,而且我还没有看到任何陷阱。

      private static class IntegerArrayList extends ArrayList<Integer> {
          IntegerArrayList () { super(); }
          IntegerArrayList (Collection<? extends Integer> c) { super(c); }
          IntegerArrayList (int initialCapacity) { super(initialCapacity); }
      }
      

      现在你可以说类似

      IntegerArrayList[][] array = new IntegerArrayList[9][9];
      

      并且像 array[1][2] 这样的元素将继承所有 ArrayList 方法(array[1][2].remove(something) 工作正常)。我创建了 private static 类,认为如果这是您唯一使用它的地方,您可以将它嵌套在其他类中,但如果您愿意,可以将其公开。另外,我从ArrayList 复制了所有三个构造函数;您可以消除不需要的,但我认为没有令人信服的理由。

      我认为问题在于 new ArrayList&lt;Integer&gt;[9][9] 被禁止,因为它会创建一个不会进行类型检查的数组(因为“类型擦除”)。但我认为添加您自己的继承自 ArrayList&lt;Integer&gt; 的非泛型类型可以恢复类型安全性。

      但我不是一般专家,如果比我知识渊博的人发现此解决方案存在问题,我也不会感到惊讶。但它对我来说似乎工作得很好,没有关于未检查类型的东西或任何东西的编译器警告。

      (PS 我把这个作为一个可能的通用解决方案来解决一个经常被问到的问题。但实际上,对于这个特定的问题,我可能只使用一个固定大小的布尔数组而不是一个 ArrayList,比如其他人,或者如果速度是一个真正的问题,我什至可能会在整数上做一些事情。)

      【讨论】:

      • IntegerArrayList 似乎是一种愚蠢的写作方式ArrayList&lt;Integer&gt;
      • @Navin 你可能已经错过了重点。关键是您不能ArrayList&lt;Integer&gt;,因为Java 关于泛型和数组的规则(特别是new ArrayList&lt;Integer&gt;[9][9] 是非法的)。因此,您需要另一种方法,一种可能性是定义一个非通用名称,即实际上是ArrayList&lt;Integer&gt; 的同义词。如果你不喜欢我选择的名字,请推荐一个更好的名字。我不擅长发明名字。但如果这是你的反对意见,请删除它,因为你误解了这个问题。
      • 我没有注意到这一点。你不能写ArrayList&lt;Integer&gt;[] table = (ArrayList&lt;Integer&gt;[])(new ArrayList&lt;?&gt;[4]);吗?只有声明的类型对泛型很重要,所以这也应该是类型安全的。
      • @Navin 这似乎可以编译,尽管带有“使用未经检查”的警告。不过,这可能没问题,因为这个 new 不会创建任何 ArrayList 对象,并且所有未来的操作都应该是类型安全的。我仍然不是仿制药专家,所以我可能遗漏了一些细微差别。如果以后再问这个问题,我会记住这个解决方案。
      猜你喜欢
      • 2015-11-29
      • 1970-01-01
      • 1970-01-01
      • 2013-11-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-31
      相关资源
      最近更新 更多