第一部分:二维数组基础概念
二维数组即“数组的数组”,常用于表示矩阵、表格等二维结构
学习目标
- 理解二维数组的内存模型
- 区分数组长度、行数、列数
- 掌握三种声明语法
内存结构示意
[
]
1
2
3
4
5
6
int[][] a = {{1,2,3}, {4,5,6}};
关键术语
- 行(row):第一维长度
length
- 列(column):第二维长度
a[0].length
- 元素访问:
a[row][col]
第二部分:二维数组创建与初始化
1
声明语法(三种写法)
// 推荐写法
int[][] matrix1;
double[][] scores;
// C 风格(不推荐)
int matrix2[][];
// 混合写法
int[] rowVector[];
int[][] matrix1;
double[][] scores;
// C 风格(不推荐)
int matrix2[][];
// 混合写法
int[] rowVector[];
2
动态初始化
// 3行4列的整型矩阵,默认值为0
int[][] grid = new int[3][4];
// 不规则数组需要先指定行数
int[][] triangle = new int[5][]; // 列稍后指定
int[][] grid = new int[3][4];
// 不规则数组需要先指定行数
int[][] triangle = new int[5][]; // 列稍后指定
3
静态初始化
// 完整写法
int[][] a = new int[][] {
{1, 2, 3},
{4, 5, 6}
};
// 简化写法(推荐)
int[][] b = {
{1, 2},
{3, 4},
{5, 6}
};
int[][] a = new int[][] {
{1, 2, 3},
{4, 5, 6}
};
// 简化写法(推荐)
int[][] b = {
{1, 2},
{3, 4},
{5, 6}
};
第三部分:访问、修改与遍历
1
读写元素
int[][] m = new int[2][3];
// 写入
m[0][0] = 100;
m[1][2] = 200;
// 读取
int val = m[0][0]; // 100
// 获取维度信息
int rows = m.length; // 2
int cols = m[0].length; // 3
// 写入
m[0][0] = 100;
m[1][2] = 200;
// 读取
int val = m[0][0]; // 100
// 获取维度信息
int rows = m.length; // 2
int cols = m[0].length; // 3
2
嵌套循环遍历
int[][] table = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// 按行遍历
for (int i = 0; i < table.length; i++) {
for (int j = 0; j < table[i].length; j++) {
System.out.print(table[i][j] + " ");
}
System.out.println();
}
// 增强for循环
for (int[] row : table) {
for (int val : row) {
System.out.print(val + " ");
}
System.out.println();
}
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// 按行遍历
for (int i = 0; i < table.length; i++) {
for (int j = 0; j < table[i].length; j++) {
System.out.print(table[i][j] + " ");
}
System.out.println();
}
// 增强for循环
for (int[] row : table) {
for (int val : row) {
System.out.print(val + " ");
}
System.out.println();
}
3
列求和示例
int[][] data = {
{1, 2, 3},
{4, 5, 6}
};
// 计算每列之和
int[] colSum = new int[data[0].length];
for (int j = 0; j < data[0].length; j++) {
int sum = 0;
for (int i = 0; i < data.length; i++) {
sum += data[i][j];
}
colSum[j] = sum;
}
System.out.println(Arrays.toString(colSum)); // [5, 7, 9]
{1, 2, 3},
{4, 5, 6}
};
// 计算每列之和
int[] colSum = new int[data[0].length];
for (int j = 0; j < data[0].length; j++) {
int sum = 0;
for (int i = 0; i < data.length; i++) {
sum += data[i][j];
}
colSum[j] = sum;
}
System.out.println(Arrays.toString(colSum)); // [5, 7, 9]
第四部分:不规则(锯齿)数组
每行列数可变的二维数组
1
创建锯齿数组
// 创建5行的三角形数组
int[][] triangle = new int[5][];
for (int i = 0; i < triangle.length; i++) {
triangle[i] = new int[i + 1]; // 第i行有i+1列
}
// 填充杨辉三角
for (int i = 0; i < triangle.length; i++) {
triangle[i][0] = triangle[i][i] = 1;
for (int j = 1; j < i; j++) {
triangle[i][j] = triangle[i-1][j-1] + triangle[i-1][j];
}
}
int[][] triangle = new int[5][];
for (int i = 0; i < triangle.length; i++) {
triangle[i] = new int[i + 1]; // 第i行有i+1列
}
// 填充杨辉三角
for (int i = 0; i < triangle.length; i++) {
triangle[i][0] = triangle[i][i] = 1;
for (int j = 1; j < i; j++) {
triangle[i][j] = triangle[i-1][j-1] + triangle[i-1][j];
}
}
第五部分:Arrays 工具类全览
java.util.Arrays 提供的静态方法让数组操作更高效
排序 sort
Arrays.sort(int[] a) // 升序
Arrays.sort(int[] a, int fromIndex, int toIndex)
int[] arr = {3, 1, 4, 1, 5};
Arrays.sort(arr); // [1, 1, 3, 4, 5]
Arrays.sort(arr, 1, 4); // 部分排序
// 二维数组按第一列排序
int[][] points = {{3,4}, {1,2}};
Arrays.sort(points, (a,b) -> a[0] - b[0]);
Arrays.sort(arr); // [1, 1, 3, 4, 5]
Arrays.sort(arr, 1, 4); // 部分排序
// 二维数组按第一列排序
int[][] points = {{3,4}, {1,2}};
Arrays.sort(points, (a,b) -> a[0] - b[0]);
查找 binarySearch
int binarySearch(int[] a, int key)
int[] sorted = {1, 3, 5, 7, 9};
int index = Arrays.binarySearch(sorted, 5); // 2
int missing = Arrays.binarySearch(sorted, 4); // -3 (插入点)
int index = Arrays.binarySearch(sorted, 5); // 2
int missing = Arrays.binarySearch(sorted, 4); // -3 (插入点)
复制 copyOf / copyOfRange
int[] src = {10, 20, 30, 40};
int[] copy = Arrays.copyOf(src, src.length); // 完全复制
int[] part = Arrays.copyOfRange(src, 1, 3); // [20, 30]
int[] copy = Arrays.copyOf(src, src.length); // 完全复制
int[] part = Arrays.copyOfRange(src, 1, 3); // [20, 30]
比较 equals / deepEquals
int[] a = {1,2,3};
int[] b = {1,2,3};
boolean same = Arrays.equals(a, b); // true
int[][] aa = {{1}, {2}};
int[][] bb = {{1}, {2}};
boolean deep = Arrays.deepEquals(aa, bb); // true
int[] b = {1,2,3};
boolean same = Arrays.equals(a, b); // true
int[][] aa = {{1}, {2}};
int[][] bb = {{1}, {2}};
boolean deep = Arrays.deepEquals(aa, bb); // true
填充 fill
int[] arr = new int[5];
Arrays.fill(arr, 99); // [99,99,99,99,99]
Arrays.fill(arr, 1, 4, 77); // [99,77,77,77,99]
Arrays.fill(arr, 99); // [99,99,99,99,99]
Arrays.fill(arr, 1, 4, 77); // [99,77,77,77,99]
转字符串 toString / deepToString
int[] nums = {1,2,3};
System.out.println(Arrays.toString(nums)); // [1, 2, 3]
int[][] matrix = {{1,2}, {3,4}};
System.out.println(Arrays.deepToString(matrix)); // [[1, 2], [3, 4]]
System.out.println(Arrays.toString(nums)); // [1, 2, 3]
int[][] matrix = {{1,2}, {3,4}};
System.out.println(Arrays.deepToString(matrix)); // [[1, 2], [3, 4]]
第六部分:二维数组常见错误
错误1:NullPointerException
int[][] arr = new int[3][]; // 只创建了行,列仍为null
arr[0][0] = 10; // NullPointerException
arr[0][0] = 10; // NullPointerException
for (int i = 0; i < arr.length; i++) {
arr[i] = new int[4]; // 初始化每一行
}
arr[i] = new int[4]; // 初始化每一行
}
错误2:ArrayIndexOutOfBoundsException
int[][] a = {
{1,2},
{3}
};
int val = a[1][1]; // 越界
{1,2},
{3}
};
int val = a[1][1]; // 越界
错误3:深浅拷贝混淆
int[][] original = {{1,2}, {3,4}};
int[][] copy = original.clone(); // 仅复制引用
copy[0][0] = 99; // original也会被修改
int[][] copy = original.clone(); // 仅复制引用
copy[0][0] = 99; // original也会被修改
int[][] deep = Arrays.stream(original)
.map(r -> r.clone())
.toArray(int[][]::new);
.map(r -> r.clone())
.toArray(int[][]::new);
第七部分:综合实战
实战:学生成绩管理系统
import java.util.*;
public class ScoreManager {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("学生人数: "); int stu = sc.nextInt();
System.out.print("课程门数: "); int course = sc.nextInt();
double[][] scores = new double[stu][course];
// 输入成绩
for (int i = 0; i < stu; i++) {
for (int j = 0; j < course; j++) {
scores[i][j] = sc.nextDouble();
}
}
// 计算每学生平均分
double[] stuAvg = new double[stu];
for (int i = 0; i < stu; i++) {
stuAvg[i] = Arrays.stream(scores[i]).average().orElse(0);
}
System.out.println("学生平均分: " + Arrays.toString(stuAvg));
}
}
public class ScoreManager {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("学生人数: "); int stu = sc.nextInt();
System.out.print("课程门数: "); int course = sc.nextInt();
double[][] scores = new double[stu][course];
// 输入成绩
for (int i = 0; i < stu; i++) {
for (int j = 0; j < course; j++) {
scores[i][j] = sc.nextDouble();
}
}
// 计算每学生平均分
double[] stuAvg = new double[stu];
for (int i = 0; i < stu; i++) {
stuAvg[i] = Arrays.stream(scores[i]).average().orElse(0);
}
System.out.println("学生平均分: " + Arrays.toString(stuAvg));
}
}
学习总结
- 二维数组本质是一维数组的数组
- 遍历二维数组务必使用嵌套循环
- 不规则数组可节省内存
- Arrays 工具类极大简化开发
- 注意深浅拷贝和越界问题