一维数组和多维数组
1.什么是数组?
数组,顾名思义就是:数据的组合。它是在内存空间中开辟一连串的存储空间,可以存储多个 具有相同数据类型的数据 。
而且数组相比于变量来讲,拥有更多的"可玩性"。
1.1 数组概述
数组是线性数据结构中最为基础,最为典型的一种顺序型结构。它用一组 连续的内存空间 ,来存储一组具有 相同类型 的数据。[1]
1.2 数据结构
数据结构是计算机存储、组织数据的方式。
数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率。数据结构往往同高效的检索算法和索引技术有关。[2]
数据结构有很多种,一般来说,按照数据的逻辑结构对其进行简单的分类,包括线性结构(线性表)和非线性结构(非线性表)两类。[3]
-
线性表(Linear List),就是表中各个结点具有线性关系。数据排成像一条线一样的结构。[1]
常见的线性表数据结构有:数组,队列、栈、链表等。
-
非线性表,就是表中各个结点之间具有多个对应关系。[3]
常见的非线性表数据结构有:树、图等。
查老师有话说: 数据结构在计算机系是一门非常重要的基础学科。数据结构产生的目的,就是为了让计算机能够以更加简单、高效、便捷的方式来 存储 和 使用 数据
2. 数组的组成
类比变量来记忆。
变量的组成:
- 数据类型
- 变量名
- 变量值
数组的组成:
-
数组的数据类型:数组存储的是一组相同数据类型的数据,需要做好指定。
-
数组名:使用数组时,也需要通过名字来使用
-
元素:数组中存储的每一个值,我们称之为元素
-
容量:长度,一个数组可以存储多少个元素( 一经定义,不可变 )
-
下标:索引,数组中每一个存储空间的 “序号”,从0开始计算
每一个下标空间,都有默认值。
数组是存储一组具有 相同数据类型 数据的 定长 空间。数组的容量为5,那么数组的下标就是0、1、2、3、4。数组容量一经定义,就不可再变。
3. 一维数组定义
3.1 一维数组
变量是一种单个值的存储方式,这种存储方式无法满足日益增多的数据需求。所以我们需要找寻一种可以同时存储多个数据的存储方式。
数组可以解决此类问题。
3.2 一维数组定义
变量的定义:
数据类型 变量名 = 变量值;
数组的定义1:(先声明,再赋值)
// 先声明数组
数据类型[] 数组名 = new 数据类型[容量];
// 数组赋值(存入值,修改值)
数组名[下标] = 元素值;
// 数组使用
数组名[下标]
数组的定义2:(声明时赋值)
// 声明时赋值
数据类型[] 数组名 = {元素1, 元素2, 元素3, ...};
// 声明时赋值
// 后期有时候只能使用这种方式
数据类型[] 数组名 = new 数据类型[] {元素1, 元素2, 元素3, ...};
极易出错,不从0 开始,
3.3 动态赋值
数组的定义1,结合循环优化,再结合上 Scanner 键盘输入,就可以将数组的赋值变为动态形式的。
// 先声明数组
数据类型[] 数组名 = new 数据类型[容量];
// 使用循环动态赋值
for (int i = 0; i < 数组的容量; i++) {
数组名[i] = 输入值;
}
// 声明数组,存储5个同学成绩
double[] scores = new double[5];
// 动态录入学生成绩
Scanner input = new Scanner(System.in);
// 数组名.length 可以获取数组的容量
for (int i = 0; i < scores.length; i++) {
System.out.print("请输入第" + (i+1) + "个学生成绩:");
scores[i] = input.nextDouble();
}
System.out.println("第3名同学成绩:" + scores[2]);
4. 数组的默认值
在原来,我们声明了一个局部变量后,如果不赋值,是无法使用的。而声明好数组之后,如果你不进行任何赋值就直接来使用,却会发现数组的各个空间竟然都有值。
这是因为在数组声明时,会伴随一个初始化动作,初始化动作就是对数组每一个空间, 根据数组元素数据类型 ,来设置一个默认值的过程。
- 整数型数组(byte、short、int、long):默认值为0
- 浮点型数组(float、double):默认值为0.0
- 布尔型数组(boolean):默认值为false
- 字符型数组(char):默认值为一个空格(\u0000)
- 字符串型数组(String):默认值为 null
double[] dArr = new double[5];
System.out.println(dArr[0]); // 0.0
int[] iArr = new int[5];
System.out.println(iArr[0]); // 0
boolean[] bArr = new boolean[5];
System.out.println(bArr[0]); // false
char[] cArr = new char[5];
System.out.println(cArr[0]); // 一个空格,\U0000
String[] sArr = new String[5];
System.out.println(sArr[0]); // null
查老师有话说:
null
是一种特殊的值,后期,我们在讲解引用数据类型时会再提到。
5. 数组的遍历
在动态赋值的实现中,我们巧妙利用了循环,实现了数组赋值的规律。其实在从数组取值过程中,依然存在此规律。在数组的常见操作中,有一种叫做遍历的概念会经常出现。
遍历: 将数组中的元素挨个取出来的过程,就叫遍历。
因为取出来的过程是一个重复、有规律性的操作,所以循环是自然少不了的。
数组遍历的方式如下:
5.1循环下标遍历
最常见的遍历方式,就是通过循环数组的下标,来进行遍历。
// 定义数组
double[] scores = {90, 80, 70, 60, 50};
// 循环下标的所有值,来遍历出数组的每一个元素
for (int i = 0; i < scores.length; i++) {
// 数组名[循环下标]
System.out.println(scores[i]);
}
5.2 forEach 循环
除此循环下标遍历之外,还有一种较为特别的方式:使用 forEach 循环(俗称增强 for 循环)遍历。这种遍历方式,主要强调的就是将数组中的元素挨个取出来,每次都临时存储到一个变量中。
// 定义数组
double[] scores = {90, 80, 70, 60, 50};
// for (数组元素数据类型 变量名 : 要遍历的数组名)
// score 是在循环中,临时存储每一个元素的变量
for (double score : scores) {
System.out.println(score);
}
增强 for 循环遍历方式与循环下标遍历相比,在使用时更简单,但前期可能不太好理解,如果实在理解不好的话,就先用循环下标的遍历方式。而且有些时候,我们需要下标来作为辅助计算因素时,采用循环下标遍历更方便。
6. 多维数组
6.1 Why?
如果要求计算一个班的5名同学的成绩和,可以使用一维数组 + 普通循环解决。
而如果是计算三个班的各5名同学的成绩和,一维数组和普通循环实现起来不够好,所以我们才需要学习更高级的概念:多维数组。
6.2 概念
多维数组,可以理解为嵌套数组。
二维数组:是以 一维数组 作为 数组元素 的数组,即 “数组的数组”。
三维数组:是以 二维数组 作为 数组元素 的数组。
多维数组的常见表现形式是二维数组、三维数组,但一般以二维数组居多。
多维数组在Java中,语法是存在的,但内存角度来看的话,只有一维数组。
6.3 定义
方式一 先声明,再赋值
二维数组本质上就是一维数组,只不过是以 一维数组 作为 数组元素 的数组。我们可以把二维数组分成外维数组及内维数组。
传统的一维数组的声明和赋值方式,我们都是掌握的。
// 数据类型[] 数组名 = new 数据类型[容量/长度];
// 存储一个班5名同学的成绩
// 成绩的数据类型:double
// 数组的容量:5
double[] scores = new double[5];
scores[0] = 90;
scores[1] = 80;
scores[2] = 70;
scores[3] = 60;
scores[4] = 50;
// 数据类型[][] 数组名 = new 数据类型[外维数组的容量][内维数组的容量];
// 存储三个班各5名同学的成绩
// 外维数组:存储的是3个班的成绩
// 内维数组:每个班的5名同学成绩
// 外维数组的数据类型:double[]
// 内维数组的数据类型:double
double[][] scores = new double[3][5];
// 存储第一个班成绩
scores[0][0] = 90; // 第一个班的第一个学生
scores[0][1] = 80;
scores[0][2] = 80;
scores[0][3] = 80;
scores[0][4] = 80;
// 存储第二个班成绩
scores[1][0] = 80;
scores[1][1] = 80;
scores[1][2] = 80;
scores[1][3] = 80;
scores[1][4] = 80;
// 存储第三个班成绩
scores[2][0] = 80;
scores[2][1] = 80;
scores[2][2] = 80;
scores[2][3] = 80;
scores[2][4] = 80;
数组也是一种数据类型 ,但是它不是普通的数据类型(int、double),数组存储的是一组相同数据类型的数据。 int[]、double[]。
二维数组:int[][]
三维数组:int[][][]
方式二 直接赋值
// 存储1个班5名同学成绩
double[] scores = {90, 80, 70, 60, 50};
double[] scores = new double[] {90, 80, 70, 60, 50};
// 存储3个班的各2名同学成绩
// 把{}看做是一个一维数组
double[][] scores = {{90, 80}, {80, 80}, {70, 70}};
double[][] scores = new double[][] {{90, 80}, {80, 80}, {70, 70}};
方式三
二维数组,定义时其实只需要指定好一维数组的容量即可。
// 存储3个班的成绩,1班3人,2班2人,3班3人
double[][] scores = new double[3][];
scores[0] = new double[3];
scores[1] = new double[2];
scores[2] = new double[3];
6.4 动态赋值
二维数组赋值虽然更为复杂,但是依然保有重复性、规律性,我们也可以用 Scanner 结合循环来优化一下。
// 定义二维数组,用来存储3个班的各5名同学成绩
double[][] scores = new double[3][5];
Scanner input = new Scanner(System.in);
// 动态录入
// 循环外维数组
for (int i = 0; i < scores.length; i++) {
System.out.println("开始录入第" + (i+1) +"班的成绩:");
// 循环内维数组
for (int j = 0; j < scores[i].length; j++) {
System.out.print((i+1) + "班的第" + (j+1) + "个学生的成绩是:");
scores[i][j] = input.nextDouble();
}
}
System.out.println("第1个班的第2名同学成绩:" + scores[0][1]);
6.5 多维数组的遍历
上述代码就是二维数组的动态赋值方式。如果去除输入赋值环节后,它显然又是二维数组的遍历方式。
double[][] scores = {{90, 80, 70, 60, 50}, {90, 90, 80, 70, 65}, {85, 70, 75, 80, 60}};
// 循环班级
for (int i = 0; i < scores.length; i++) {
// 循环每个班级
System.out.println((i+1) + "班的学生成绩如下:");
for (int j = 0; j < scores[i].length; j++) {
System.out.println("第" + (j+1) + "个学生的成绩是:" + scores[i][j]);
}
}
7. Arrays工具类
API:Application Programming Interface 应用程序接口。
Arrays 是 Java 提供的数组操作类,提供了大量的数组操作方法。
它和 Scanner 一样,都是在 java.util
包下的,所以在使用时也需要先 import
先导入一下。
有了 Arrays,你只需要一行代码,就可以搞定一个数组的遍历输出操作。
package demo1;
// 1.导入 Arrays
import java.util.Arrays;
public class Demo1 {
public static void main(String[] args) {
String[] arr = {"佩奇", "乔治", "苏西"};
// 2.使用 Arrays(它不需要创建对象,直接可以用)
String arrStr = Arrays.toString(arr);
System.out.println(arrStr); // [佩奇, 乔治, 苏西]
}
}
Arrays 工具类还有更多的数组操作方法,可以去查阅 Java 官方的 API 文档,来挑选适合你的数组操作方法。
[1] 冯小圆. 数据结构之数组[EB/OL].www.cnblogs.com/fengxiaoyua…](https://www.cnblogs.com/fengxiaoyuan/p/10934399.html). 2019-05-27
[2] 彭军、向毅主编.数据结构预算法:人民邮电出版社,2013年
[3] 刘亚东;曲心慧编.C/C++常用算法手册:中国铁道出版社,2017.09:第21页