08. 一维数组和多维数组

1.什么是数组?

数组,顾名思义就是:数据的组合。它是在内存空间中开辟一连串的存储空间,可以存储多个 具有相同数据类型的数据

而且数组相比于变量来讲,拥有更多的"可玩性"。

1.1 数组概述

数组是线性数据结构中最为基础,最为典型的一种顺序型结构。它用一组 连续的内存空间 ,来存储一组具有 相同类型 的数据。[1]

1.2 数据结构

数据结构是计算机存储、组织数据的方式。

数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率。数据结构往往同高效的检索算法索引技术有关。[2]

数据结构有很多种,一般来说,按照数据的逻辑结构对其进行简单的分类,包括线性结构(线性表)和非线性结构(非线性表)两类。[3]

  1. 线性表(Linear List),就是表中各个结点具有线性关系。数据排成像一条线一样的结构。[1]

    常见的线性表数据结构有:数组,队列、栈、链表等。

    img

  2. 非线性表,就是表中各个结点之间具有多个对应关系。[3]

    常见的非线性表数据结构有:树、图等。

    img

查老师有话说: 数据结构在计算机系是一门非常重要的基础学科。数据结构产生的目的,就是为了让计算机能够以更加简单、高效、便捷的方式来 存储使用 数据

2. 数组的组成

类比变量来记忆。

变量的组成:

  1. 数据类型
  2. 变量名
  3. 变量值

数组的组成:

  1. 数组的数据类型:数组存储的是一组相同数据类型的数据,需要做好指定。

  2. 数组名:使用数组时,也需要通过名字来使用

  3. 元素:数组中存储的每一个值,我们称之为元素

  4. 容量:长度,一个数组可以存储多少个元素( 一经定义,不可变

  5. 下标:索引,数组中每一个存储空间的 “序号”,从0开始计算

    每一个下标空间,都有默认值。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Td3nlczG-1613828484081)(F:\Software\Java\day09_一维数组\03_pic\2021-02-20_20-07-44.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7DWBAHot-1613828484082)(F:\Software\Java\day09_一维数组\03_pic\394345c282f84ce7a68ff4331debf896~tplv-k3u1fbpfcp-zoom-1.image.png)]

数组是存储一组具有 相同数据类型 数据的 定长 空间。数组的容量为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;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-spmOyN6k-1613828484085)(F:\Software\Java\day11_多维数组\03_pic\0b532c5d318f4411bddd361a7978fd25~tplv-k3u1fbpfcp-zoom-1.image.png)]

数组也是一种数据类型 ,但是它不是普通的数据类型(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先导入一下。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lbmn4oL7-1613828484085)(F:\Software\Java\day11_多维数组\03_pic\2021-02-20_21-36-38.png)]

有了 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页

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值