1. 数组遍历
操作数组时,最常见的操作就是遍历。通过for 循环即可遍历数组——因为数组的每个元素都可以通过索引来访问,因此使用标准的for循环就能完成遍历:
publicclassMain{publicstaticvoidmain(String[]args){int[]ns={1,4,9,16,25};for(inti=0;i<ns.length;i++){intn=ns[i];System.out.println(n);}}}上述for循环中,初始条件i = 0,因为索引从0开始。
1.1 标准 for 循环遍历
第一种方式:使用标准for循环,通过索引访问每个元素。
1.2 for-each 循环遍历
第二种方式是使用for-each 循环,直接迭代数组的每个元素:
publicclassMain{publicstaticvoidmain(String[]args){int[]ns={1,4,9,16,25};for(intn:ns){System.out.println(n);}}}1.3 打印数组内容
直接打印数组变量,得到的是数组在 JVM 中的引用地址:
int[]ns={1,1,2,3,5,8};//[I@b4c966a要打印数组的元素内容,可以使用 for-each 循环:
int[]ns={1,1,2,3,5,8};for(intn:ns){System.out.print(n+", ");}然而,使用 for-each 循环逐元素打印仍比较繁琐。Java 标准库提供了Arrays.toString(),可以快速打印数组内容:
// 遍历数组importjava.util.Arrays;publicclassMain{publicstaticvoidmain(String[]args){int[]ns={1,1,2,3,5,8};System.out.println(Arrays.toString(ns));}}1.4 练习:倒序遍历数组
请按倒序遍历数组并打印每个元素:
publicclassMain{publicstaticvoidmain(String[]args){int[]ns={1,4,9,16,25};for(inti=ns.length-1;i>=0;i--){System.out.println(ns[i]);}}}2. 数组排序
对数组进行排序是程序中非常基础的需求。常用的排序算法有冒泡排序、插入排序和快速排序。
2.1 冒泡排序算法
以冒泡排序为例,对整型数组从小到大排序的核心思路如下:
2.1.1 算法步骤
- 比较相邻的元素:如果第一个比第二个大(升序排序),则交换它们两个;
- 逐对处理:对每一对相邻元素做同样的工作,从第一对到最后一对;本轮结束后,最后的元素会是最大的数;
- 排除已排定元素:针对所有元素重复以上步骤,排除最后已排定的元素;
- 循环直至有序:持续对越来越少的数据重复上述步骤,直到没有任何一对数字需要比较为止。
2.1.2 完整代码实现
importjava.util.Arrays;publicclassMain{publicstaticvoidmain(String[]args){int[]ns={28,65,33,95,3,7,65};System.out.println("排序前:"+Arrays.toString(ns));//排序之前for(inti=0;i<ns.length-1;i++){for(intj=0;j<ns.length-i-1;j++){if(ns[j]>ns[j+1]){// 交换ns[j]和ns[j+1]:inttmp=ns[j];ns[j]=ns[j+1];ns[j+1]=tmp;}}System.out.println("第"+(i+1)+"轮后:"+Arrays.toString(ns));}}}2.1.3 执行过程详解
排序前数组:[28, 65, 33, 95, 3, 7, 65]
第 1 轮详解(i = 0):
| j 值 | 比较 (ns[j] > ns[j+1]) | 结果 | 数组状态 |
|---|---|---|---|
| 0 | 28 > 65 | false(不交换) | [28, 65, 33, 95, 3, 7, 65] |
| 1 | 65 > 33 | true(交换) | [28, 33, 65, 95, 3, 7, 65] |
| 2 | 65 > 95 | false(不交换) | [28, 33, 65, 95, 3, 7, 65] |
| 3 | 95 > 3 | true(交换) | [28, 33, 65, 3, 95, 7, 65] |
| 4 | 95 > 7 | true(交换) | [28, 33, 65, 3, 7, 95, 65] |
| 5 | 95 > 65 | true(交换) | [28, 33, 65, 3, 7, 65, 95] |
冒泡排序的核心特点:每一轮循环后,当前未排定部分的最大值会被“浮”到末尾;因此,下一轮循环的结束位置可前移一位,无需再比较已排定的尾部元素。
2.2 变量交换的正确方式
特别注意:交换两个变量的值必须借助临时变量。如下写法是错误的:
//ns[j] = 1; ns[j+1] = 2;ns[j]=ns[j+1];//ns[j] = 2ns[j+1]=ns[j];//ns[j+1] = 2,并未完成交换正确写法如下:
intx=1;inty=2;intt=x;x=y;y=t;//完成交换2.3 使用 JDK 内置排序
实际上,Java 标准库已内置排序功能,只需调用Arrays.sort()即可实现排序:
importjava.util.Arrays;publicclassMain{publicstaticvoidmain(String[]args){int[]ns={28,33,65,3,7,65,95};Arrays.sort(ns);System.out.println(Arrays.toString(ns));}}Arrays.sort()执行后,变量ns指向的数组内容会被直接改变(原地排序)。
2.4 练习:实现降序排序
请思考如何用冒泡排序实现降序排序:
// 降序排序importjava.util.Arrays;publicclassMain{publicstaticvoidmain(String[]args){int[]ns={28,12,89,73,65,18,96,50,8,36};// 排序前:System.out.println(Arrays.toString(ns));for(inti=0;i<ns.length-1;i++){for(intj=0;j<ns.length-i-1;j++){if(ns[j]<ns[j+1]){inttemp=ns[j];ns[j]=ns[j+1];ns[j+1]=temp;}}}System.out.println(Arrays.toString(ns));if(Arrays.toString(ns).equals("[96, 89, 73, 65, 50, 36, 28, 18, 12, 8]")){System.out.println("测试成功");}else{System.out.println("测试失败");}}}| ** j值** | 比较 (ns[j] > ns[j+1]) | 结果 | 数组状态 |
|---|---|---|---|
| 0 | 28 > 65 | false(不交换) | [28, 65, 33, 95, 3, 7, 65] |
| 1 | 65>33 | true (交换) | [28, 33, 65, 95, 3, 7, 65] |
| 2 | 65>95 | false(不交换) | [28, 33, 65, 95, 3, 7, 65] |
| 3 | 95>3 | true (交换) | [28, 33, 65, 3, 95, 7, 65] |
| 4 | 95>7 | true (交换) | [28, 33, 65, 3, 7, 95, 65] |
| 5 | 95>65 | true (交换) | [28, 33, 65, 3, 7, 65,95] |
冒泡排序的特点是,每一轮循环后,最大的一个数被交换到末尾,因此,下一轮循环就可以“刨除”最后的数,每一轮循环都比上一轮循环的结束位置靠前一位。
另外,注意到交换两个变量的值必须借助一个临时变量。像这么写是错误的:
//ns[j] = 1; ns[j+1] = 2;ns[j]=ns[j+1];//ns[j] = 2ns[j+1]=ns[j];//ns[j+1] = 2 并没有完成交换正确写法是:
intx=1;inty=2;intt=x;x=y;y=t;//完成交换实际上,Java标准库内置了排序功能,只需要调用JDK提供的Arrays.sort()就可以排序:
importjava.util.Arrays;publicclassMain{publicstaticvoidmain(String[]args){int[]ns={28,33,65,3,7,65,95};Arrays.sort(ns);System.out.println(Arrays.toString(ns));}}Arrays.sort()排序后,变量ns指向的数组内容被改变。
练习
请思考如何实现对数组进行降序排序:(冒泡排序降序)
// 降序排序importjava.util.Arrays;publicclassMain{publicstaticvoidmain(String[]args){int[]ns={28,12,89,73,65,18,96,50,8,36};// 排序前:System.out.println(Arrays.toString(ns));for(inti=0;i<ns.length-1;i++){for(intj=0;j<ns.length-i-1;j++){if(ns[j]<ns[j+1]){inttemp=ns[j];ns[j]=ns[j+1];ns[j+1]=temp;}}}System.out.println(Arrays.toString(ns));if(Arrays.toString(ns).equals("[96, 89, 73, 65, 50, 36, 28, 18, 12, 8]")){System.out.println("测试成功");}else{System.out.println("测试失败");}}}3. 多维数组
3.1 二维数组
二维数组就是数组的数组。定义一个二维数组的示例如下:
publicclassMain{publicstaticvoidmain(String[]args){int[][]ns={{1,2,3,4},{4,5,6,7},{7,8,9,0}};System.out.println(ns.length);}}因为ns包含 3 个数组,所以ns.length为 3。ns在内存中的结构如下:
┌───┬───┬───┬───┐ ┌───┐ ┌──▶│1│2│3│4│ ns ─────▶│░░░│──┘ └───┴───┴───┴───┘ ├───┤ ┌───┬───┬───┬───┐ │░░░│─────▶│4│5│6│7│ ├───┤ └───┴───┴───┴───┘ │░░░│──┐ ┌───┬───┬───┬───┐ └───┘ └──▶│7│8│9│0│ └───┴───┴───┴───┘3.1.1 访问与打印二维数组
定义一个普通数组arr0,然后将ns[0]赋值给它,即可拿到二维数组中的第一行数据:
importjava.util.Arrays;publicclassMain{publicstaticvoidmain(String[]args){int[][]ns={{1,2,3,4},{4,5,6,7},{7,8,9,0}};System.out.println(ns.length);//打印二维数组长度System.out.println(ns[0][0]);//访问二维数组的某个元素System.out.println(Arrays.deepToString(ns));//用Arrays.deepToString()打印二维数组int[]arr0=ns[0];System.out.println(arr0.length);//打印{1,2,3,4}长度System.out.println(Arrays.toString(arr0));// 输出 [1, 2, 3, 4]}}关键要点:
- 使用
ns[行][列]来访问二维数组的某个元素; - 使用
Arrays.deepToString()可以快速打印多维数组的全部内容; ns[i]本身是一个一维数组引用,可赋值给普通数组变量。
3.2 三维数组
三维数组就是二维数组的数组。定义一个三维数组的示例如下:
int[][][]ns={{{1,2,3},{4,5,6},{7,8,9}},{{10,11},{12,13}},{{14,15,16},{17,18}}};它在内存中的结构如下:
┌───┬───┬───┐ ┌───┐ ┌─▶│1│2│3│ ┌─▶│░░░│──┘ └───┴───┴───┘ │ ├───┤ ┌───┬───┬───┐ │ │░░░│────▶│4│5│6│ │ ├───┤ └───┴───┴───┘ │ │░░░│──┐ ┌───┬───┬───┐ ┌───┐ │ └───┘ └─▶│7│8│9│ ns ───▶│░░░│──┘ └───┴───┴───┘ ├───┤ ┌───┐ ┌───┬───┐ │░░░│────▶│░░░│────▶│10 │11 │ ├───┤ ├───┤ └───┴───┘ │░░░│──┐ │░░░│──┐ ┌───┬───┐ └───┘ │ └───┘ └─▶│12 │13 │ │ └───┴───┘ │ ┌───┐ ┌───┬───┬───┐ └─▶│░░░│ ───▶│14 │15 │16 │ ├───┤ └───┴───┴───┘ │░░░│──┐ ┌───┬───┐ └───┘ └─▶│17 │18 │ └───┴───┘如果要访问三维数组的某个元素,例如ns[2][0][1],只需按索引逐层定位即可找到对应的最终元素15。
3.3 练习:计算学生平均分
使用二维数组表示一组学生的各科成绩,请计算所有学生的平均分:
publicclassMain{publicstaticvoidmain(String[]args){// 用二维数组表示的学生成绩:int[][]scores={{82,90,91},// 学生甲的语数英成绩{68,72,64},// 学生乙的语数英成绩{95,91,89},// ...{67,52,60},{79,81,85},};doubleaverage=0;intcount=0;for(int[]score:scores){// 使用 for-each 循环遍历每行for(inti:score){average+=i;count++;}}average/=count;System.out.println(average);if(Math.abs(average-77.733333)<0.000001){System.out.println("测试成功");}else{System.out.println("测试失败");}}}**第 1 次外层循环:**score 变成第一行 {82, 90, 91}。
内层循环开始:依次把 82、90、91 取出来累加。
**第 2 次外层循环:**score 变成第二行 {68, 72, 64}。
内层循环开始:依次把 68、72、64 取出来累加。
**第 3 次外层循环:**score 变成第三行 {95, 91, 89}……
声明:本文内容为本人基于 廖雪峰 Java 教程 进行实操学习后的个人笔记与代码实践记录。
文中所有知识点、代码示例及讲解均源自上述网站,著作权归原作者廖雪峰及其团队所有。本文仅用于个人学习总结与知识分享,不涉及任何商业用途。如涉及侵权,请联系删除。