Logo

郎哥编程

数组结构

2021-06-07 137

学习目标:掌握数组结构及其使用。

理解数组结构

前面介绍的数据类型都是基本数据类型,例如整型、字符型、浮点型等数据,这些都是简单的数据类型。对于有些数据,只有简单的数据类型是不够的,难以反映出数据的特点,也难以有效地进行处理。

例如:假设需要接收并存储100个学员的成绩,此时无法使用for循环依次读取每个学员的成绩,因为在for循环中只通过一个变量依次存储这些值,这样,for循环运行结束后只能保存最后一个学员的成绩,而前面99个学员的成绩都无法找回。因此,在这种情况下,只能通过声明100个变量,并且编写100个nextFloat()和printf()语句,来接收和输出用户输入的学员成绩。那么,如果要求处理5000个学员的成绩呢,岂不要定义5000个存储成绩的变量?

日常生活中有大量的数据类似于此,它们有相同的类型,需要的处理方法也一致,为了实现对这些数据统一表达和处理,Java语言提供了“数组”这一数据结构,数组可以把同一类型的数据有序进行排列,进行同一存储和操作。数组结构如下图所示;

 11.png

数组是有序数据的集合,其结构的最大特征就是通过有序编号固定集合内每个数据的位置(数组结构如上图所示)。有序编号被称为下标,被固定的每个数据被称为元素。数组内所包含元素的数据类型没有限制,可以是任意类型的数据,如数值、字符串、布尔型、对象、数组。下标值是一个从0开始的连续正整数。上图的0、1、2、length-2、length-1为数组元素的下标,其中length是数组包含元素的个数,length-2为数组倒数第二个元素,length-1为数组最后一个元素。程序可以通过下标访问数组中的元素。

数组的所有元素在内存中连续存储,其所有元素的数据类型必须相同。不能将数据类型不同的数据存储在同一个数组中。不管数组中含有多少个元素,该数组都将只有一个名称。数组的大小或长度是可容纳元素的最大数量。在数组的处理过程中,如果数组的下标值超过此大小,将会导致程序运行过程中发生不可预知的结果,因此在使用数组时,必须确保数组容纳元素的数量不能超过数组规定的大小。

下图显示了数组中涉及的概念,包括数组的名称、大小、数组中的元素及数组的下标。

12.png

上图显示了名称为Rate的数组及其四个元素,数组名称后面方括号中的数字是数组可容纳元素的最大数量,也称为数组的长度,数组的小标标明了元素在数组中的位置。

数组是Java语言中一种非常重要的数据类型,是具有相同的数据类型且按一定次序排列的一组变量的集合体,构成一个数组的这些变量称为数组元素。数组有一个统一的名称,通过名称和数组下标可以访问数组中的任意元素。

数组结构的维数

前面介绍的数组结构都是多行单列数据结构,行数为数组的长度,列为数组中的元素。如前面的Rate数组有四行一列,因此其数组长度为4,列元素分别为1.5、3.2、0.09、36.5。结构如下图所示:

13.png

多行单列的数组结构也可以用表格来表示,上图的数组结构就可以用4行1列的表格来表示:

14.JPG

类似于上图的数据结构,我们称之为一维数组,一维数组中只有一列数据,数据可以通过下标获取,下标为0的是1.5,下标为1的是3.2,下标为2的是0.09,下标为3的是36.5。

在用程序解决实际问题中,经常会遇到类似下面问题。例如,有50名学员,现在需要存储每名学员的序号和两门课程的成绩。数据结构可用如下表格所示:

15.JPG

表格结构为50行3列结构,要存储类似上面表格结构的数据,用前面介绍的一维数组不能满足存储要求。因为一维数组只能存储1列数据,现在有3列数据。用什么数据结构存储上述表格的数据呢?试想一下,如果一维数组的每个元素本身也是一维数组,就可以存储上述表格数据,数据结构如下图所示:

14.png

上图所示的数据结构中,Students为数组的名称,数组的长度为50,其数组元素本身也是一个长度为3的数组,该数组有三个元素,分别对应学员序号、语文成绩、数学成绩,其中下标0对应学员序号,下标1对应语文成绩,下标2对应数学成绩。这样就可以根据第一个数组和第二个数组的下标访问一个学员的学号、语文、成绩。例如:如果需要访问学员2的数学成绩,可以通过Students[1][2]来访问学员2的数学成绩,Students[1][2]是访问数组的语法;再如,如果需要访问学员50的语文成绩,可以通过Students[49][1]来访问学员50的语文成绩。

类似于上面的数据结构,我们称之为二维数组,二维数组本质上是以数组作为数组元素的数组,访问二维数组的元素时,需要同时给出第一个数组的小标和第二个数组的下标。

进一步考虑,在上述例子中,如果学员的语文和数学成绩按学期来进行存储,其数据结构可用如下表格所示:

16.JPG

上面的表格结构为50行3列结构,但在语文和数学列单元中又嵌套了一个3行1列的子表,二维数组无法存储上面的表格数据。如果把语文和数学列单元的数据也用一个数组表示,就可以满足上述表格数据存储要求了,其数据结构如下图所示:

15.png

上图所示的数据结构中,Students为数组的名称,数组的长度为n,其数组元素本身也是一个长度为3的数组,该数组有三个元素,分别对应学员序号、语文成绩、数学成绩,其中语文成绩和数学成绩元素本是也是一个数组,该数组长度为n,记录了n个学期的考试成绩。这样就可以根据第一个数组、第二个数组的下标访问一个学员的学号,根据第一个数组、第二个数组和第三个数组的下标访问学员的学期成绩。例如:如果需要访问第一个学员的学员学号,可以通过Students[0][0]来访问第一个学员的学员学号;访问第一个学员语文第一学期的成绩,可以通过Students[0][1][0]来访问;访问第一个学员语文第n学期的成绩,可以通过Students[0][1][n]来访问。

类似于上面存储语文和数学学期成绩的数据结构,我们称之为三维数组,三维数组本质上是三层数组的嵌套,分为第一层数组、第二层数组、第三层数组。第一层数组的元素是第二层数组,第二层数组的元素是第三层数组。访问三维数组的元素时,需要同时给出三个数组的下标。

可以类推,数组的数据结构可有四维数组、甚至更多维数组,随着数组维数的增多,其数据存储复杂度和计算复杂度也相应提升。在编程应用中,一般常用的为一维数组、二维数组和三维数组。

对数组的访问一般是通过下标进行的。在一维数组中,数组的下标是由一个数字构成的,通过这一个数字组成的下标对数组的内容进行访问;在二维数组中,数组的下标是由两个数字构成的,通过这两个数字组成的下标对数组的内容进行访问;在三维数组中,数组的下标是由三个数字构成的,通过这三个数字组成的下标对数组的内容进行访问。

一维数组

前面讨论过一维数组的概念,一维数组只有一个下标。

声明一维数组

在java语言中,声明一维数组的语法为:

类型说明符  数组名[];

其中类型说明符可以是Java语言中任何有效的数据类型,如int、float、char等。数组名是数组的名称,数组名的命名需符合变量命名规则。

例如:

int  a[];

 //定义了一个数组,名称为a,数组中的元素类型是int

float   score[];

//定义了一个数组,名称为float,数组中的元素类型是float

一维数组的初始化

声明了一个数组,只是得到了一个存放数组的地址变量,并没有为数组元素分配内存空间,因而不能直接使用,必须经过初始化,为数组分配内存空间才能使用。

数组的初始化有两种方法,一种是静态初始化,另一种是动态初始化。

(1)静态初始化

在声明数组时,直接给数组的每个元素赋上一个初始值。静态初始化一般在数组元素比较少时使用。

静态初始化的语法为:

数组类型  数组名[]={值1, 值2,……, 值2};

例如:

int  a[] = {26,67,89,106,210};
float  score[] = {87.5,67.2,96.8,92.6,75.9};
char  chArray[] = {‘a’,’m’,’o’,’p’,’q’};

对于数组a,可以看出数组中有5个元素,分别是a[0]、a[1]、a[2]、a[3]、a[4]、a[5],即数组下标从0开始,这5个元素的数值依次为a[0]=26、a[1]=67、a[2]=89、a[3]=106、a[4]=210。其在内存中结构如下图所示:

16.png

错误的初始化:

int  a[];
a[] = {26,67,89,106,210};

数组的初始化只能在声明中完成,不能声明完成后,再进行初始化。

(2)动态初始化

有时,数组并不需要在声明时就赋初值,而是在使用时才进行赋值。另外,有些数组比较大,元素非常多,用静态初始化不方便,这样就需要使用动态初始化。数组的动态初始化使用new操作符。

动态初始化的方式有两种。

(1)先声明数组,再用new分配内存

例如:

int  a[];
a = new  int[4];

Java的new运算操作符,用来在内存中申请存储空间,并将申请到存储空间的首地址赋值给被申请的变量。语句a = new  int[4]为数组a分配了4个元素,这4个元素分别是a[0]、a[1]、a[2]、a[3],它们的值都为0。

(2)在定义数组的同时用new分配内存

例如:

int  a[] = new  int[4];
int  size = 100;

//也可以用变量给出数组的大小

float  score[] = new float[size];

一维数组元素的访问

使用数组的最基本操作是数组元素的访问,对数组的使用最终都通过对元素的使用而实现。数组的元素通过数组下标进行访问。前面已经讲过,在Java语言中,数组下标是从0开始的,所以包含n个元素的数组下标的范围是0到n-1。例如:前面定义的数组a,其下标范围为0到4。要访问a数组的元素,可通过a[0]、a[1]、a[2]、a[3]、a[4]访问a数组的各个元素,此时,方括号中的数字是数组的下标,表示访问数组的第几个元素。

在Java语言中,数组也是一种对象,对象将在后面的学习单元讲述。数组被初始化后就确定了它的长度,对于每个已经分配了存储空间的数组,Java用一个数据成员length来存储这个数组的长度值。

例如:

int  a[] = {26,67,89,106,210};
int  i;
for( i = 0; i < a.length; i++ )
{
   System.out.printf("第 %d 数组元素的值为: %d;\n",a[i]);   
}

在遍历数组的for循环中,循环条件为a.length,a.length就是数组长度的值,在a数组中,a.length的值为5。

下面通过一个完整的示例,演示如何声明一个数组,并通过nextFloat方法为数组动态赋值。

案例13:创建一个一维数组,用来记录5件商品的单价。商品单价由用户输入,最后遍历数组输出商品的单价和5件商品的总价。

在Punit4项目unit包下创建Case13类。代码如下:

package unit;
import java.util.Scanner;
 
public class Case13 {
    public static void main(String[] args) {
        /**
         * 声明并初始化存储商品价格的数组
         * 该数组有5个元素,数据类型是float
         */
        float price[] = new float[5];
        // 声明存储商品总价的变量,并初始化为0.0
        float total = 0.0f;
        // count为循环次数
        int count = 5;
        // i为循环变量
        int i;
        Scanner sc = new Scanner(System.in);
        // 循环接收用户输入的5个商品价格
        for (i = 0; i < count; i++) {
            System.out.printf("请输入 %d 个商品的价格: ", i + 1);
            // 用户输入的第i件商品价格赋值给price数组的第i个元素
            price[i] = sc.nextFloat();
            total += price[i];
        }
        System.out.println("*****商品小计******");
        // 循环输出商品的价格:
        for (i = 0; i < count; i++) {
            System.out.printf("第 %d 件商品价格为: %.2f;\n", i + 1, price[i]);
        }
        System.out.printf("商品价格合计为: %.2f", total);
 
    }
}

程序功能主要是演示数组声明、初始化、动态赋值、输出数组元素的使用方法。

程序声明包含5个元素的数组price,用来存储用户输入的5件商品价格,并通过循环获取用户输入的商品价格,同时计算商品总价,商品总价存储到声明的变量total中。然后,循环输出每件商品的价格,最后输出商品总价。

可以把一维数组看作超市商品货柜中一列存放同类商品的格子,商家如果要把商品放到格子中,需要提前向超市申请格子的使用权,超市同意使用后,商家才能把商品放到格子中,然后根据格子的编号存取商品。再回到编程中来,程序要使用一维数组,必须要向计算机操作系统申请数组的使用权以及使用空间大小,操作系统分配给数组存储空间后,程序方可使用。因此,数组在使用中必须先声明并初始化后才能使用,声明和初始化数组的目的是为其留出所需要的存储空间,用来存储数组元素。

二维数组

在实际问题中有些数据信息是二维的或者多维的。多维数组元素有多个下标,以标识它在数组中的位置。本课只介绍二维数组,多维数组可由二维数组类推而得到。

声明二维数组

二维数组的声明与一维数组类似,只是需要给出两对方括号,声明二维数组的语法为:

类型说明符   数组名[][];

例如:

int  a[][];

double  score[][];

其中,声明语句的第一个方括号可以称为行数组,第二个方括号可以称为列数组。

二维数组的初始化

同一维数组类似,二维数组在使用前也要进行初始化。初始化也分为动态初始化和静态初始化。

 (1)静态初始化

静态初始化是在数组声明时,对声明的数组元素赋初值的过程。

例如:

int  array[][] = {{3,-9,6},{8,0,1},{11,9,8}};

声明并初始化数组array,它有3个元素,每个元素又都是有3个元素的一维数组。外层大括号对里面的元素是行数组的元素,因为行数组元素是一维数组,因此每个行数组元素也用大括号对包括起来,里面的元素是列数组的元素。

另外,用指定初值的方式对数组进行初始化时,列数组元素的个数可以不同。

例如:

int  array[][] = {{3,6},{8,0,1},{11,9,8}};

此时,第一个列数组的元素个数是2,第二个和第三个列数组的元素个数是3个。

(2)动态初始化

动态初始化同一维数组相同,也是先声明数组,然后通过new运算符分配内存。语法格式为:

类型说明符  数组名[][] = new 类型说明符[数组长度][];

或:

类型说明符  数组名[][] = new 类型说明符[数组长度][ 数组长度];

例如:

int  array[][];
array = new int[3][];
array = new int[3][3];

使用数组的最基本操作是数组元素的访问,对数组的使用最终都通过对元素的使用而实现。数组的元素通过数组下标进行访问。前面已经讲过,在Java语言中,数组下标是从0开始的,所以包含n个元素的数组下标的范围是0到n-1。例如:前面定义的数组a,其下标范围为0到4。要访问a数组的元素,可通过a[0]、a[1]、a[2]、a[3]、a[4]访问a数组的各个元素,此时,方括号中的数字是数组的下标,表示访问数组的第几个元素。

二维数组元素的访问

二维数组的元素通过两个下标进行访问,分别是行数组下标和列数组下标,例如:对于二维数组a,可通过a[i][j]进行访问,其中i和j为数组a的下标。二维数组行数组的长度可通过a.length获取,列数组的长度可通过a[i]. length获取。

例如:

int  a[][] = {{3,-9,6},{8,0,1},{11,9,8}};
int  i,j;
for( i = 0; i < a.length; i++ )
{
 for(j=0; j<a[i]. length;j++)
System.out.printf("a[ %d][%d] 数组元素的值为: %d;\n",i,ja[i][j]);   
}

在遍历数组的外层for循环中,循环条件为a.length,a.length就是行数组长度的值,在内层for循环中,循环条件为a[i]. length,a[i]. length为当前行数组第i个元素数组的长度。

二维数组的存储结构

前面array数组的存储结构如下图所示:

17.png

下面通过一个完整的示例,演示如何声明一个二维数组,赋值并输出。

案例14:用二维数组实现同学通讯录。

在Punit4项目unit包下创建Case14类。代码如下:

package unit;
import java.util.Scanner;
 
public class Case14 {
    public static void main(String[] args) {
        /**
         * 声明并初始化存储同学通讯录的二维数组
         * 该二维数组中行数组有3个元素
         * 列数组有2个元素,分别存储姓名、联系电话
         */
        String phone[][] = new String[3][2];
        // count为循环次数
        int count = 3;
        // i为循环变量
        int i;
        Scanner sc = new Scanner(System.in);
 
        // 循环接收用户输入的同学的姓名和电话
        for (i = 0; i < count; i++) {
 
            System.out.printf("请输入 %d 个同学的姓名: ", i + 1);
            phone[i][0] = sc.next();
            System.out.printf("请输入 %d 个同学的电话: ", i + 1);
            phone[i][1] = sc.next();
        }
        System.out.println("*****同学通讯录******");
        // 循环二维数组
        for (i = 0; i < count; i++) {
            System.out.printf("姓名:%s  联系电话:%s \n", phone[i][0], phone[i][1]);
        }
 
    }
}

程序功能主要是演示二维数组声明、初始化、动态赋值、输出数组元素的使用方法。

程序声明一个二维数组phone,其中行数组有3个元素,存储3个同学的信息,列数组有2个元素,分别存储同学的姓名和电话。程序通过循环依次获取用户输入的3位同学的姓名和电话,并存储到二维数组中。最后,循环输出每位同学的姓名和电话号码。

二维数组用于描述多行多列的数据结构。例如:超市的商品货柜可以用二维数组进行描述,商品货柜是由多行和多列组成的网格,商品货柜的行号和列号可以确定唯一的格子单元;再如:学校教室课桌的安排也是多行多列的数据结构,课桌的位置由课桌所在的行数和课桌所在的列数确定。

代码在线纠错(通义千问 qwen-max)

支持粘贴多个代码文件,提交后由阿里云通义千问自动分析代码漏洞、语法错误、逻辑问题并给出修改建议。
您已解锁 AI 代码纠错功能,可正常使用!

评论区

登录 后发表评论
暂无评论