第八章 多维数组

课本笔记 第八章

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。

      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 array
        int[][] m = getArray();

        //Display sum of elements
        System.out.println("\nSum of all elements is " + sum(m));
    }

    public static int[][] getArray() {
        //Create a Scanner
        Scanner input = new Scanner(System.in);

        //Enter array values
        int[][] 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 questions
        char[][] 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 questions
        char[] keys = {'D', 'B', 'D', 'C', 'C', 'D', 'A', 'E', 'A', 'D'};

        //Grade all answers
        for (int i = 0; i < answers.length; i++) {
            //Grade one student
            int 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 points
        double[][] 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 points
        int p1 = 0, p2 = 1;
        double shortestDistance = distance(points[p1][0], points[p1][1],
                points[p2][0], points[p2][1]);

        //Compute distance for every two points
        for (int i = 0; i < points.length; i++) {
            for (int j = i + 1; j < points.length; j++) {
                //Find distance
                double distance = distance(points[i][0], points[i][1],
                        points[j][0], points[j][1]);
                if (shortestDistance > distance) {
                    //Update p1 and p2
                    p1 = i;
                    p2 = j;
                    //Update shortestDistance
                    shortestDistance = distance;
                }
            }
        }

        //Display result
        System.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 solution
        int[][] grid = readASolution();

        System.out.println(isValid(grid) ? "Valid solution" : "Invalid solution");
    }

    /**
     * Read a Sudoku solution from the console
     */
    public static int[][] readASolution() {
        //Create a Scanner
        Scanner 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 valid
        return 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 column
        for (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 column
        for (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 box
        for (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 valid
        return true;
    }
    /* 输入的数据
    9 6 3 1 7 4 2 5 8
    1 7 8 3 2 5 6 4 9
    2 5 4 6 8 9 7 3 1
    8 2 1 4 3 7 5 9 6
    4 9 6 8 5 2 3 1 7
    7 3 5 9 6 1 8 2 4
    5 8 9 7 1 3 4 6 2
    3 1 7 2 4 6 9 8 5
    6 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 file
        for (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 humidity
        for (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 result
            System.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 determined
        int 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 Scanner
        Scanner 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);
    }
}
posted @ 2021-10-07 16:09  Wozen  阅读(147)  评论(0)    收藏  举报