8.1 引言
- 表或矩阵中的数据可以表示为二维数组
8.2 二维数组基础
- 二维数组中的元素通过行和列的下标来访问
8.2.1 声明二维数组变量并创建二维数组
- 下面是声明二维数组的语法:
数据类型 [][] 数组名;
- 或者
数据类型 数组名 [][];允许这种方式,但不推荐使用它
- 可以使用这个语法创建5 × 5 的 int 型二维数组,并将它赋给matrix;
matrix = new int[5][5];
- 二维数组中使用两个下标,一个表示行,另一个表示列。同一维数组一样,每个下标索引值都是int型的,从0开始,如图8-1a所示。
- 使用matrix[2,1]访问行下标为2、列下标为1的元素是一种常见的错误。在Java中,每个下标必须放在一对方括号中。
- 也可以使用数组初始化简写方式来声明、创建和初始化一个二维数组。
8.2.2 获取二维数组的长度
- 二维数组实际上是一个其中每个元素都是一个一维数组的数组。数组x的长度是数组中元素的个数,可以用x.length获取该值。元素x[0],x[1], … ,x[x.length - 1]也是数组。可以使用x[0].length,x[1].length, … , x[x.length -1 ].length获取它们的长度
8.2.3 不规则数组
- 二维数组中的每一行本身就是一个数组,因此,各行的长度就可以不同。这样的数组称为不规则数组(ragged array)。下面就是一个创建不规则数组的例子
- 如果事先不知道不规则数组的值,但知道它的长度,如前面讲到的,可以使用如下所示的语法创建不规则数组
int[][] triangleArray = new int[5][];triangleArray[0] = new int[5];triangleArray[1] = new int[4];triangleArray[2] = new int[3];triangleArray[3] = new int[2];triangleArray[4] = new int[1];
- 现在可以给数组赋值,例如:
triangleArray[0][3] = 4;triangleArray[4][0] = 5;
- 使用语法 new int[5] [] 创建数组时,必须指定第一个下标。语法 new int[] []是错误的。
8.3 处理二维数组
- 嵌套的for循环常用于处理二维数组
- 假设如下创建数组matrix:
int[][] matrix = new int[10][10];
- 下面是一些处理二维数组的例子:
- (使用输入值初始化数组)下面的循环使用用户输入值初始化数组:
java.util.Scanner input = new java.util.Scanner(System.in);System.out.println("Enter " + matrix.length + " rows and " +matrix[0].length + " columns: ");for(int row = 0; row < matrix.length; row++){for(int column = 0; column < matrix[row].length;column++){matrix[row][column] = input.nextInt();}}
- (使用输入值初始化数组)下面的循环使用用户输入值初始化数组:
- (使用随机值初始化数组)下面的循环使用0到99之间的随机值初始化数组:
for(int row = 0; row < matrix.length; row++){for(int column = 0; column < matrix[row].length;column++){matrix[row][column] = (int)(Math.random() * 100);}}
- (打印数组)为打印一个二维数组,必须使用如下所示的循环打印数组中的每个元素
for(int row = 0; row < matrix.length; row++){for(int column = 0; column < matrix[row].length;column++){System.out.print(matrix[row][colume] + " ");}System.out.println();}
- (对所有元素求和)使用名为total的变量存储和。将total初始化为0。利用类似下面的循环,把数组中的每一个元素都加到total上:
int total = 0;for(int row = 0; row < matrix.length; row++){for(int column = 0; column < matrix[row].length;column++){total += matrix[row][column];}}
- (按列求和)对于每一列,使用名为total的变量存储它的和。利用类型下面的循环,将该列中的每个元素加到total上:
for(int column = 0; column < matrix[0].length;column++){int total = 0;for(int row = 0; row < matrix.length; row++){total += matrix[row][column];}System.out.println("Sum for column " + column + " is " + total);}
- (哪一行的和最大)使用变量maxRow和indexOfMaxRow分别跟踪和的最大值以及该行的下标值。计算每一行的和,如果计算出的新行的和更大,就更新maxRow和indexOfMaxRow。 ```java int maxRow = 0; int indexOfMaxRow = 0;
//Get sum of the first row in maxRow for(int column = 0; column < matrix[0].length; column++){ maxRow += matrix[0][column]; }
for(int row = 1; row < matrix.length; row++){ int totalOfThisRow = 0; for(int column = 0; column < matrix[row].length;column++){ totalOfThiRow += matrix[row][column]; } if(totalOfThisRow > maxRow){ maxRow = totalOfThisRow; indexOfMaxRow = row; } } System.out.println(“Row “ + indexOfMaxRow
- “ has the maximum sum of “ + maxRow); ```
(随机打乱)在7.2.6节中已经介绍了如何打乱一维数组的元素,那么如何打乱二维数组中的所有元素呢?为了实现这个功能,对每个元素matrix[i] [j] ,随机产生下标 i1 和 j1,然后互换matrix[i] [j] 和matrix[i1] [j1],如下所示:
for(int i = 0; i < matrix.length; i++){for(int j = 0; j < matrix[i].length ; j++){int i1 = (int)(Math.random * matrix.length);int j1 = (int)(Math.random * matrix[i].length);//Swap matrix[i][j] with matrix[i1][j1]int temp = matrix[i][j];matrix[i][j] = matrix[i1][j1];matrix[i1][j1] = temp;}}
8.4 将二维数组传递给方法
- 将一个二维数组传递给方法时,数组的引用传递给了方法
程序清单 8-1 PassTwoDimensionalArray.java
import java.util.Scanner;public class PassTwoDimensionalArray {public static void main(String[] args) {//Get an arrayint[][] m = getArray();//Display sum of elementsSystem.out.println("\nSum of all elements is " + sum(m));}public static int[][] getArray() {//Create a ScannerScanner input = new Scanner(System.in);//Enter array valuesint[][] m = new int[3][4];System.out.println("Enter " + m.length + " rows and "+ m[0].length + " columns: ");for (int i = 0; i < m.length; i++) {for (int j = 0; j < m[i].length; j++) {m[i][j] = input.nextInt();}}return m;}public static int sum(int[][] m) {int total = 0;for (int row = 0; row < m.length; row++) {for (int column = 0; column < m[row].length; column++) {total += m[row][column];}}return total;}}
8.5 示例学习:多选题
- 编写一个可以进行多选题测验评分的程序
程序清单 8-2 GradeExam.java
public class GradeExam {/*** Main method*/public static void main(String[] args) {//Students' answers to the questionschar[][] answers = {{'A', 'B', 'A', 'C', 'C', 'D', 'E', 'E', 'A', 'D'},{'D', 'B', 'A', 'B', 'C', 'A', 'E', 'E', 'A', 'D'},{'E', 'D', 'D', 'A', 'C', 'B', 'E', 'E', 'A', 'D'},{'C', 'B', 'A', 'E', 'D', 'C', 'E', 'E', 'A', 'D'},{'A', 'B', 'D', 'C', 'C', 'D', 'E', 'E', 'A', 'D'},{'B', 'B', 'E', 'C', 'C', 'D', 'E', 'E', 'A', 'D'},{'B', 'B', 'A', 'C', 'C', 'D', 'E', 'E', 'A', 'D'},{'E', 'B', 'E', 'C', 'C', 'D', 'E', 'E', 'A', 'D'}};//Key yo the questionschar[] keys = {'D', 'B', 'D', 'C', 'C', 'D', 'A', 'E', 'A', 'D'};//Grade all answersfor (int i = 0; i < answers.length; i++) {//Grade one studentint correctCount = 0;for (int j = 0; j < answers[i].length; j++) {if (answers[i][j] == keys[j]) {correctCount++;}}System.out.println("Student " + i + " 's correct count is " + correctCount);}}}
8.6 示例学习:找出距离最近的点对
- 本节提供一个几何问题的解决 —- 找到距离最近的点对
- 一种直观的方法就是计算所有点对之间的距离,并且找出最短的距离,它的实现如程序清单8-3所示
程序清单 8-3 FindNearestPoints.java
import java.util.Scanner;public class FindNearestPoints {public static void main(String[] args) {Scanner input = new Scanner(System.in);System.out.print("Enter the number of points: ");int numberOfPoints = input.nextInt();//Create an array to store pointsdouble[][] points = new double[numberOfPoints][2];System.out.print("Enter " + numberOfPoints + " point: ");for (int i = 0; i < points.length; i++) {points[i][0] = input.nextDouble();points[i][1] = input.nextDouble();}//p1 and p2 are the indices in the points' array//Initial two pointsint p1 = 0, p2 = 1;double shortestDistance = distance(points[p1][0], points[p1][1],points[p2][0], points[p2][1]);//Compute distance for every two pointsfor (int i = 0; i < points.length; i++) {for (int j = i + 1; j < points.length; j++) {//Find distancedouble distance = distance(points[i][0], points[i][1],points[j][0], points[j][1]);if (shortestDistance > distance) {//Update p1 and p2p1 = i;p2 = j;//Update shortestDistanceshortestDistance = distance;}}}//Display resultSystem.out.println("The closest two points are " + "(" + points[p1][0]+ ", " + points[p1][1] + ") and (" + points[p2][0] + ", " + points[p2][1] + ")");}public static double distance(double x1, double y1, double x2, double y2) {return Math.sqrt(Math.pow((x2 - x1), 2) + Math.pow((y2 - y1), 2));}}
- 也可能会有不止一对具有相同最小距离的点对。本程序只需找到这样的一对点。可以在编程练习题8.8中修改这个程序,找出所有距离最短的点对。
- 从键盘输入所有的点是很烦琐的。可以将输入存储在一个名为FindeNearestPoints.txt的文件中,并使用下面的命令编译和运行这个程序:
java FindNearestPoints < FindNearestPoints.txt
8.7 示例学习:数独
- 要解决的问题是检验一个给定的数独解决方案是否正确。
- 本节介绍一个每天都会出现在报纸上的有趣问题。这是一个关于数字放置的问题,通常称为数独(Sudoku)。它是一个非常有挑战性的问题。为了使之能被编程新手接受,本节给出数独问题的简化版本,即检验某个解决方案是否正确。数独问题的完整解决方案放在补充材料VI.C中
- 数独是一个9×9的网格,它被分为更小的3×3的盒子(也称为区域或者块),如图8-4所示。一些称为固定方格(fixed cell)的格子里放置了从1到9的数字。该程序的目标是将从1到9的数字放入那些称为自由方格(free cell)的格子,以使得每行每列以及每个3×3的盒子都包含从1到9的数字,如图8-4b所示。
程序清单 8-4 FindNearestPoints.java
import java.util.Scanner;public class CheckSudokuSolution {public static void main(String[] args) {//Read a Sudoku solutionint[][] grid = readASolution();System.out.println(isValid(grid) ? "Valid solution" : "Invalid solution");}/*** Read a Sudoku solution from the console*/public static int[][] readASolution() {//Create a ScannerScanner input = new Scanner(System.in);System.out.println("Enter a Sudoku puzzle solution: ");int[][] grid = new int[9][9];for (int i = 0; i < 9; i++) {for (int j = 0; j < 9; j++) {grid[i][j] = input.nextInt();}}return grid;}/*** Check whether a solution is valid*/public static boolean isValid(int[][] grid) {for (int i = 0; i < 9; i++) {for (int j = 0; j < 9; j++) {if (grid[i][j] < 1 || grid[i][j] > 9 || !isValid(i, j, grid)) {return false;}}}//The solution is validreturn true;}/*** Check whether grid[i][j] is valid in the grid*/public static boolean isValid(int i, int j, int[][] grid) {//Check whether grid[i][j] is unique in j's columnfor (int column = 0; column < 9; column++) {if (column != j && grid[i][column] == grid[i][j]) {return false;}}//Check whether grid[i][j] is unique in j's columnfor (int row = 0; row < 9; row++) {if (row != i && grid[row][j] == grid[i][j]) {return false;}}//Check whether grid[i][j] is unique in the 3-by-3 boxfor (int row = (i / 3) * 3; row < (i / 3) * 3 + 3; row++) {for (int col = (j / 3) * 4; col < (j / 3) * 3 + 3; col++) {if (!(row == i && col == j) && grid[row][col] == grid[i][j]) {return false;}}}//The current value at grid[i][j] is validreturn true;}/* 输入的数据9 6 3 1 7 4 2 5 81 7 8 3 2 5 6 4 92 5 4 6 8 9 7 3 18 2 1 4 3 7 5 9 64 9 6 8 5 2 3 1 77 3 5 9 6 1 8 2 45 8 9 7 1 3 4 6 23 1 7 2 4 6 9 8 56 4 2 5 9 8 1 7 3*/}
8.8 多维数组
- 二维数组由一个一维数组的数组组成,而一个三维数组可以认为是由一个二维数组的数组所组成的
- 可以对二维数组变量的声明以及二维数组的创建方法进行推广,用于声明n ≥ 3的 n维数组变量和创建n维数组
8.8.1 示例学习:每日温度和湿度
- 在文件中,天是从1到10编号的,而小时是从1到24编号的。因为数组下标是从0开始的,所以,data[][][0] [0] [0] 存储的是第1天第1小时的温度,而data[9] [23] [1]存储的是第10天第24小时的湿度。
- 该程序在程序清单8 - 5 中给出
程序清单 8-5 Weather.java
import java.util.Scanner;public class Weather {public static void main(String[] args) {final int NUMBER_OF_DAYS = 10;final int NUMBER_OF_HOURS = 24;double[][][] data = new double[NUMBER_OF_DAYS][NUMBER_OF_HOURS][2];Scanner input = new Scanner(System.in);//Read input using input redirection from a filefor (int k = 0; k < NUMBER_OF_DAYS * NUMBER_OF_HOURS; k++) {int day = input.nextInt();int hour = input.nextInt();double temperature = input.nextDouble();double humidity = input.nextDouble();data[day - 1][hour - 1][0] = temperature;data[day - 1][hour - 1][1] = humidity;}//Find the average daily temperature and humidityfor (int i = 0; i < NUMBER_OF_DAYS; i++) {double dailyTemperatureTotal = 0, dailyHumidityTotal = 0;for (int j = 0; j < NUMBER_OF_HOURS; j++) {dailyTemperatureTotal += data[i][j][0];dailyHumidityTotal += data[i][j][1];}//Display resultSystem.out.println("Day " + i + " 's average temperature is " +dailyTemperatureTotal / NUMBER_OF_HOURS);System.out.println("Day " + i + " 's average humidity is "+ dailyHumidityTotal / NUMBER_OF_HOURS);}}}
数据文件: 链接:https://pan.baidu.com/s/1ALH2WrGT6owqJDhcnWyaIQ
提取码:1024 网址:https://liveexample.pearsoncmg.com/data/Weather.txt
8.8.2 示例学习:猜生日
程序清单 8-6 GuessBirthdayUsingArray.java
import java.util.Scanner;public class GuessBirthdayUsingArray {public static void main(String[] args) {//Day to be determinedint day = 0;int answer;int[][][] dates = {{{1, 3, 5, 7},{9, 11, 13, 15},{17, 19, 21, 23},{25, 27, 29, 31}},{{2, 3, 6, 7},{10, 11, 14, 15},{18, 19, 22, 23},{26, 27, 30, 31}},{{4, 5, 6, 7},{12, 13, 14, 15},{20, 21, 22, 23},{28, 29, 30, 31}},{{8, 9, 10, 11},{12, 13, 14, 15},{24, 25, 26, 27},{28, 29, 30, 31}},{{16, 17, 18, 19},{20, 21, 22, 23},{24, 25, 26, 27},{28, 29, 30, 31}}};//Create a ScannerScanner input = new Scanner(System.in);for (int i = 0; i < 5; i++) {System.out.println("Is your birthday in Set" + (i + 1) + " ? ");for (int j = 0; j < 4; j++) {for (int k = 0; k < 4; k++) {System.out.printf("%4d", dates[i][j][k]);}System.out.println();}System.out.print("\nEnter 0 for No and 1 for Yes: ");answer = input.nextInt();if (answer == 1) {day += dates[i][0][0];}}System.out.println("Your birthday is " + day);}}
