我该如何在Java中操作二维数组?

3
我正在学习Java考试,2D数组让我感到困难。我已经掌握了基础知识,例如创建和初始化2D数组,但是当需要插入、删除或排序时,我会感到相当困惑。我的教授只花了10分钟讲解了基础概念,但在考试中,我们需要知道如何创建一个对象的二维数组并通过在数组中插入、删除和排序对象来操作数据。他要求我们在考试中手写所有代码,因此不能使用计算机辅助完成。我花费了几个小时研究这里和其他网站上的示例,但我仍然感觉无法掌握足够的知识手写所有的代码并且正确地实现它。
我的困惑主要源于嵌套循环通常用于遍历2D数组。我可以看到其他人是如何做的并复制那样做,但我仍然不明白为什么循环按照它们所做的方式工作。我确信我在这方面是少数派,但出于某种原因,它背后的逻辑完全使我迷失了。
以我一直在努力理解2D数组和考试材料的(尽管很差)例子为例。假设你经营一家汽车经销商,并且想订购汽车以填充你的库存。程序首先使用一个描述出售的汽车的顶级抽象类(在我的例子中是奥迪)开始。经销商提供4种奥迪车型,分别为A4、A6、A8和R8。所有这些汽车(类)都继承自超类,名为Audi的方法。然后我想创建一个2D数组来存储汽车库存。这将在由我定义的另一个类中使用,包括了一些方法,例如search()、delete()和sort()。让我们称其为AudiDealership。经销商只能容纳每种车型的3辆汽车,因此该数组将类似于Audi[4][3]。A4会占据第一行,下标为0,A6会占据下标1,以此类推。我应该如何设置循环来从正确的行插入/删除?显然,我不希望将A4插入到应该容纳A6等的行中。

我可以整天盯着代码并复制它,但我希望能够理解循环的工作原理和方式。如果这个话题看起来微不足道或者已经被过度讨论了,我表示歉意,但在发布这篇文章之前,我所做的所有阅读都让我感到困惑。你们这个网站上的许多人都是出色的老师,所以我认为有人可能能够用一种我可以理解的方式来解释这个问题。我的教授在这方面没有提供任何帮助,所以我正在使用外部手段来尝试弄清楚事情。非常感谢您提前提供任何建议或解释 :)


1
你可能读过这个吗?http://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html 这是一个很好的资源,可以帮助你理解如何处理数组。如果你懂得如何操作单个数组,那么二维数组就是一个数组的数组,一旦你掌握了这个概念,就更容易理解它了。 - user2336315
二维数组的简明解释 - gtgaxiola
3个回答

2

把二维数组看作是包含其他数组的数组会有所帮助,例如Cars[0][5]访问了一个在0位置的汽车数组,而实际的汽车位于该数组中的第5个位置。Cars[1][5]将访问第二个汽车数组,在位置1处找到的汽车是在位于位置1的数组中的第5个。以下代码可能会帮助您更好地理解:

public class TwoDArray {

  public static void main(String[] args)
  {      
    Cars[][] cars; // declaring my 2D array.

    cars = new Cars[4][]; // making the x axis 4 cars wide.

    // now we will step along the x axis and create a Cars array in each slot.
    for ( int a = 0; a < cars.length; a++) // cars.length = how wide.
    { 
        cars[a] = new Cars[3]; // creating a new Cars[] in each slot of our 2D Car array @ position a.
                               //cars[a] = new 1D Cars array in slot a, length of 3.
    }

    // Note that we could have also created our array like this.
    // Cars[][] cars = new Cars[4][3];


    for ( int x = 0; x < cars.length; x++) //stepping along the x axis. cars.length = how wide.
    {   //every time we step thru x we will execute this next loop.
        for ( int y = 0; y < cars[x].length; y++) // stepping along the y axis. cars[x].length = how long.
        { // this loop will cycle through the y axis each time we increment x
            cars[x][y] = new Cars( 2014, "someAudi", x + " " + y ); // creating a new car(s) @ x,y position.
        }
    }

    // now to just print them.

    for ( int x = 0; x < cars.length; x++) //stepping along the x axis again.
    {
        for ( int y = 0; y < cars[x].length; y++) // stepping along the y axis.
        {
            System.out.println(cars[x][y].getYear() + 
                    " " + cars[x][y].getModel() +
                    " " + cars[x][y].getName() +
                    " " + cars[x][y].getManufacturer()); // the super method.
        }
    }

    //INSERTION. 

    // To insert into your array, you simply need to provide the coordinates to insert the new Car(s) object.
    // This next line will insert a new Car into the array at position 1 and the number 2 element of that array.
    cars[1][2] = new Cars( 2014, "someAudi", "My Favorite Car!");

    System.out.println(); // Just adding a space between outputs.

    for ( Cars[] c: cars) //extracting each Cars array and name it c from the 2D Cars array named cars.
    {                     //basically stepping along the x axis and getting each array stored in x.

        for ( Cars car: c) // Now we are stepping along the y axis.
        {                  // We are getting each individual Cars object and naming it car
                           // from each Cars[] named c from our first loop.

            System.out.println(car.getYear() + 
                    " " + car.getModel() +
                    " " + car.getName() +
                    " " + car.getManufacturer()); // the super method.
        }
    }

    // NOTE* if you wish to insert a new element and do not have extra capacity then you will need to
    // create a larger array @ cars[x]. cars[x] = new Cars[newSize];. 

    // DELETION.

    // To delete an element you can just simply overwrite it. 
    // such as:        
    cars[1][1] = new Cars( 2014, "someAudi", "new Audi"); // Essentially we deleted and inserted a new object
                                                          // at position [1][1]. 

    // If you just want to completely remove the element then you will need to update the size of the array.

    // You can define a new array to hold the values of the old array minus the element that should be deleted.
    Cars[] newArray = new Cars[cars[2].length - 1]; // We will use the array stored in cars[2] for this example.
                                                    // we set the length to one less to completely get rid of the
                                                    // old element.    

    int deleteThisPosition = 1; // We will use this variable to store the position that will be deleted from
                                // the array stored in cars[2].

    int newArrayPosition = 0; // We will use this to increment our position in the new array along with `a`
                              // in the next for loop.

    for ( int a = 0; a < cars[2].length; a++)
    {
        if ( a == deleteThisPosition) // if it reaches this position we will advance `a` and exclude it from
             a++;                     // our new array.

        newArray[newArrayPosition] = cars[2][a]; // we will store the value @ position `a` from the array in cars[2]
                                                 // into our newArray @ position `newArrayPosition`.                                     

        newArrayPosition++; // incrementing our variable to stay parallel with the array in cars[2]. 
    }

    //Now we can just assign the newArray to cars[2]. You will notice that Car `2 1` is no longer present.
    cars[2] = newArray;

    System.out.println(); // Just adding a space between outputs.

    for ( Cars[] c: cars) 
    {                                 
        for ( Cars car: c) 
        {                                 
            System.out.println(car.getYear() + 
                    " " + car.getModel() +
                    " " + car.getName() +
                    " " + car.getManufacturer()); // the super method.
        }
    }

  }
}

以下是与您示例相关的其他类别。

Audi 类:

public abstract class Audi { 

  public String getManufacturer() { return "Audi"; } // method from this super class.

}

汽车类:
public class Cars extends Audi{ //extending Audi.

  private String model;
  private String name;
  private int year;

  Cars(int year, String model, String name)
  {
    this.year = year;
    this.model = model;
    this.name = name;
  }

  public String getName() { return name; }    

  public String getModel() { return model; }

  public int getYear() { return year; }

}

如果您运行代码,您将会注意到汽车名称中的模式。
输出:
请注意每辆汽车名称中的模式,即唯一列。它对应于我们如何遍历循环。我们从 x 开始,对于每个 x,我们循环 y。在上面的代码中,x + " " + y 是我们给每辆汽车命名的方式。

太棒了!这让我理解循环如何通过数组移动。你的评论使代码易于阅读,我知道它在每次迭代中的功能如何。非常感谢 :) 为什么我的教授无法构建像那样的东西超出了我的理解。 - FuegoJohnson
我很高兴能够提供帮助。 - MarGar
我更新了我的答案,包括插入和删除,以防你还需要这方面的帮助。此外,我还添加了增强型循环,以防你也想了解它们。如果你愿意,可以忽略增强型循环,因为我只是用它们来打印数组。 - MarGar
非常感谢!自从你发布这个(在插入和删除之前),我一直在玩弄一些代码,我觉得我开始掌握它了!有了你添加的其余部分,我在周一的测试时会感到更加自信。我真的很感激你的帮助性意见。有像你这样的人,有时才使编程社区变得如此棒 :) - FuegoJohnson
就增强型for循环而言,我以前用过几次普通数组,我的教授上周在课堂上简要介绍了它们,但我从未真正理解它们的要点,所以感谢您的补充。我总是愿意学习新东西,因此当涉及到增强型循环时,更少的代码量带来的便利是我应该更加熟悉的东西。 - FuegoJohnson

1
让我举个例子:
StringBuilder output = new StringBuilder();

    for (int i = 0; i < table.length; i++) {
        for (int j = 0; j < table[i].length; j++) {
            output.append(table[i][j]);
        }
        output.append("\n");
    }

这是遍历二维数组的代码。

array image

代码直接进入第一行。这是i值。 由于您想循环遍历该行的每一列,您需要知道该行的长度以便进行循环。
因此,您从第一行开始,向右到达末尾,即table [i] .length。 在第一行中,第一个长度将是table [0] .length。 而这个长度为3,因为每行有3列。

entry point

现在我们已经循环完第一行,进入第二行。 进入第二行时,i增加1。 所以我们的指针现在指向第2行(table[i].length中的 i 现在为1,因为它始终从0开始),以此类推。
我们的指针遍历每一行,这就是它的工作原理。 随着每一行的到来, i 的指针会增加1(这是for循环中的 i++ )。

enter image description here

随着每一行新列的增加,j 增加,而 i 保持不变。只有当您输入新行时,i 才会更改。通过输入新列来更改 j。希望这可以帮助您 ;)

EDIT.:

另一个例子:

如果您想获取第4行中第3列的值: enter image description here

您想要的值在这里:table[3][2]; 请记住,数组始终从0开始计数。 :)


哇,视觉效果真的帮了很多!不知道为什么,对我来说最难的部分就是可视化。加上你对每个部分的解释,我感觉现在比以前更理解了。虽然还不是100%,但我可以尝试编写一些代码,希望能够弄清楚。非常感谢! :) - FuegoJohnson
没问题,我刚开始也遇到了同样的问题。随时问吧 :) - BigPenguin

1
Audi[4][3] cars = ... // your 2D array of all cars

正如您正确指定的那样,

A4将填充第一行,下标为0,A6填充下标1,依此类推。

这意味着 cars[0] 包含 Audi[] with A4 instancescars[1] 包含 Audi[] with A6 instances 等等。

好的,所以

 Audi[] A4s = cars[0];
 Audi[] A6s = cars[1];
 ...

那么你可以说
 Audi A4_1 = A4s[0];
 Audi A4_2 = A4s[1];
 Audi A4_3 = A4s[2];
 ...

对于每一辆车,您希望重复此过程。但这是错误的方法。首先我们需要通用化访问每辆汽车。

如果您想遍历每个型号数组中特定的汽车,您需要使用一个名为specificCarIndex的索引的for循环。遍历A4s数组将是简单的:

 for (int specificCarIndex = 0; specificCarIndex < 3; specificCarIndex++) {
      // Here A4s[specificCarIndex] contains an object of concrete Audi car of model A4
  }

要遍历另一个模型的数组(如A6),您需要执行相同的操作,将A4s替换为A6s等等。

现在我们需要将所有内容概括起来。

  for (int carModelIndex = 0; carModelIndex < 4; carModelIndex++) {
      // Here cars[carModelIndex] holds an array of specific Audi model as you mentioned before
  }

cars[carModelIndex]实质上是Audi[] A4s,如果carModelIndex == 0,那么就是Audi[] A6s,以此类推。

现在我们知道了如何访问每个Audi型号的数组,也知道了如何访问每个型号数组中的单个汽车,我们将两者结合起来:

 for (int carModelIndex = 0; carModelIndex < 4; carModelIndex++) {
     for (int specificCarIndex = 0; specificCarIndex < 3; specificCarIndex++) {
         // Here cars[carModelIndex][specificCarIndex] holds an object of type Audi which refers to a specific car
         // If double index seems difficult, consider this:
         // Audi[] audis = cars[carModelIndex] (array like A4s, A6s...)
         // Audi audi = audis[specificCarIndex] (specific car)
         // Just as in the examples before for-loops.
     }    
 }

谢谢回答我关于如何在数组中搜索特定汽车的问题。你的变量名帮助我理解了循环块与我的示例相关的工作原理。因为你们都提供了有用的建议,所以选择一个答案会很困难 :) - FuegoJohnson

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