Java数组

数组的定义

什么是数组?

数组是一种特殊的数据类型,这种数据类型用于存储一组数据类型相同的数据。简单来说,数组就是一个容器,用于存储一组数据,这组数据具有相同的数据类型

数组中的每个数据称为数组的元素。

有如下需求:某幼儿园有一个小班,班里有10个小朋友,要记录每个小朋友的年龄,如何记录?

方法一:定义10个 int 类型变量,每个变量保存一个小朋友的年龄。

方法二:定义1个 int 类型数组,数组中保存10个小朋友的年龄。

数组具有2个特点:

1. 数组中的元素具有相同的数据类型。

2. 数组的容量是确定的。---创建数组的时候确定其容量。

注意:

数据类型分为:基本数据类型和引用类型。

1.基本数据类型: byte、short、int、long、float、double、char、boolean

2.引用数据类型:数组、类、接口

为什么要使用数组?

在开发中,数组使用非常频繁。例如:新闻App的新闻列表页面,就是一组新闻;电商项目要统计每天的订单情况,订单也是一组数据;购物网站的商品列表,也是一组数据...几乎所有的软件都有这种成组出现的数据。因此数组使用场景无处不在。

使用数组有以下原因:

1. 简化代码:数组能存储一组数据,因此可以将多个变量合为一个变量。

表示一组数据,可以定义多个变量,但是代码量大。使用数组的话,只需要一个变量就能存储一组数据。

2. 便于批量操作数据:数组和循环经常搭配使用,通过循环可以操作每一个数据。

例如:有一组订单,现在需要对订单按天进行统计销售额。可以使用一个循环,遍历每一个订单,属于同一天的订单进行求和。 如果每个订单都用一个变量保存的话,就没有办法使用循环进行操作。

如何定义数组?

数组的定义格式:

格式一: 数据类型[] 变量名

例如: int[] ages

含义:定义一个整型数组,数组的名字叫ages。

格式二: 数据类型 变量名[]

例如: int ages[]

含义:定义一个整型数组,数组的名字叫ages。

推荐使用格式一。1. 便于理解;2.很多程序员都在使用格式一,便于阅读彼此的代码

格式二是为了兼容C语言的写法,便于C程序员转型为Java程序员。

数组的初始化

变量定义的三要素:数据类型 、变量名、初始值。

数组是一种数据类型,在定义数组变量的时候,也要为其指定初始值。数组的初始值指的是数组中每个元素的初始值。

数组的初始化分为2种:动态初始化 和 静态初始化。

动态初始化

动态初始化:在初始化数组时,只指定数组长度,由系统为其分配初始值。

数组长度:数组所能容纳的元素的个数。

数组元素的默认初始值

动态初始化格式:数据类型[] 变量名 = new 数据类型[数组长度];

示例: int[] ages = new int[10];

上述代码定义了一个int类型的数组,数组名是ages,数组的元素个数是10,每个元素都是int类型,每个元素的初始值是0。

等号左边:

1. int 表示数组中的元素是int类型。

2. [] 表示这是一个数组。

3. ages是数组名称,即变量名。

等号右边:

1. new 为数组申请堆区内存空间。申请的内存空间是连续的,内存空间的大小取决于元素类型 和元素个数。

2. int 表示数组中的元素是int类型。

3. []表示是一个数组,[10]表示数组能容纳10个数据。

4. 因为是动态初始化,系统为每个int元素分配的初始值是0。

静态初始化

静态初始化:初始化数组时,人为指定每个元素的值。

格式一: 数据类型[] 变量名 = new 数据类型[]{数据1,数据2,数据3,...};

格式一示例: int[] ages = new int[]{3, 4, 4, 3, 2, 4, 3, 4, 3, 3};

上述代码定义了一个int数组,数组名是ages,数组中包含10个int数据。它们的初始值不再是系统默认给的0,而是我们人为指定的初始值。

等号左边:

1. int 表示数据元素是int类型。

2. [] 表示这是一个数组。

3. ages是数组名,即变量名。

等号右边:

1. new 为数组申请堆内存空间。申请的内存空间是连续的,内存空间的大小取决于元素类型和元素个数。

2. int 表示数组中的元素是 int类型。

3. [] 表示这是一个数组。-----注意不要写元素个数。

4. {3, 4, 4, 3, 2, 4, 3, 4, 3, 3} 表示数组中每个元素的初始值。大括号中写了几个值,数组的元素个数就是几。

格式二:-----格式二是格式1的简化格式,通常使用这种格式。

数据类型[] 变量名 = {数据1, 数据2, 数据3,...};

格式二示例: int[] ages = {3, 4, 4, 3, 2, 4, 3, 4, 3, 3};

格式二定义的数组和格式一含义一样,只是格式一的简化形式。

数组访问

数组访问包括:数组的访问、数组元素的访问。

数组的访问

数组在内存中是一段连续的内存区域。

数组名是一个变量,但是它不存储具体数据,存储的是这段连续内存区域的起始地址(也叫首地址)。

数组名代表的是整个数组,不代表数组中的元素。

数组变量的访问方式:数组名

在打印数组变量的时候,会打印出数组所存储的内存地址。

数组元素的访问

格式:数组名[索引]

索引指的是数据的序号(编号),通常也称为数组的下标。在Java中数组下标是从0开始的。即第1个数据下标为0,第2个数据下标为1,第3个数据下标为2,...

数组名[索引] 等同于一个变量,是一种特殊的变量名。

索引的最小值是:0,索引的最大值是:元素个数 - 1

数组元素的访问包括:给数组元素的赋值、使用数组元素的值。

给数组元素赋值

public static void main(String[] args) {
    int[] ages =  {3, 4, 3, 2, 5};
    System.out.println(ages[0]);
    ages[0] = 7;//此处将ages[0]的值赋值为7,会覆盖原有的3
    System.out.println(ages[0]);
}

使用数组元素的值

public static void main(String[] args) {
    int[] ages =  {3, 4, 3, 2, 5};
    System.out.println(ages[0]);
    ages[0] = 7;//此处将ages[0]的值赋值为7
    System.out.println(ages[0]);
    int num = ages[1];//将ages[1]赋值给变量num
    int sum = ages[2] + ages[3];//将ages[2]于ages[3]的和赋值给sum
    System.out.println(num);
    System.out.println(sum);
}

数组访问总结

1. 数组名代表的是整个数组,存储的是数组的起始地址。

2. 数组元素是数组中真正的数据,数组元素的访问方式是 数组名[索引]

3. 索引的最小值是:0,最大值是:元素个数-1

数组的内存分配

栈区和堆区

Java语言对内存做了若干个分区,最为重要的2个分区是:堆区和栈区

栈区:用于存放局部变量的内存区域。

局部变量:方法内定义的变量,包括方法的参数。

栈区由系统管理,系统为每个变量分配一个区域。以栈的方式管理变量的生命周期。

堆区:唯一一个程序员可以操作和使用的内存区域。

堆区必须通过new来开辟空间。

程序员只负责开辟和使用堆区空间,Java的垃圾回收机制会在堆区内存不再使用的时候,回收开辟的区域。

数组的内存

public static void main(String[] args) {
    //array变量是局部变量,array变量存放在栈区,有系统管理array变量的生命周期。
//虽然array自己存放在栈区,但是array变量的值 是数组的起始地址,存的是new新开辟的12个字节的首地址。
    int[] array = new int[3];
    System.out.println(array);//此处打印的是数组的起始地址(堆区)
    System.out.println(array[0]);// 0
    System.out.println(array[1]);// 0
    System.out.println(array[2]);// 0
    array[0] = 20;//数组元素的赋值
    array[2] = 10;//数组元素的赋值
    array[1] = array[0] + array[2];//数组元素的赋值
    System.out.println(array[0]);// 20 
    System.out.println(array[1]);// 30
    System.out.println(array[2]);// 10
}

下面是创建数组array的内存分配图:

对于 int[] array = new int[3];这行代码,可以细分为4个步骤:

1. 定义局部变量array,数据类型是 int[],局部变量被存放在了内存的栈区。对应代码:int[] array

2. 通过new关键字,在堆区开辟一段连续的内存空间,开辟的空间大小是12个字节。这段内存空间的首地址是15db9742。之所以开辟12个字节,是因为需要存放3个int数据,每个int是4个字节,所以是12个字节。

3. 系统为数组的3个元素设置默认值0。因为是动态初始化,所以系统来设置默认初始值,int类型元素的初始值默认是0。-----步骤2和3对应的代码是: new int[3]

4. 将数组的首地址赋值给变量array,因此array的值是地址15db9742

因此执行下面4行代码时

System.out.println(array);//此处打印的是数组的起始地址(堆区),即15db9742
System.out.println(array[0]);// 0
System.out.println(array[1]);// 0
System.out.println(array[2]);// 0

打印的结果分别是:

[I@15db9742

0

0

0

下面6行代码是给数组元素赋值,并打印元素的值。

array[0] = 20;//数组元素的赋值
array[2] = 10;//数组元素的赋值
array[1] = array[0] + array[2];//数组元素的赋值
System.out.println(array[0]);// 20 
System.out.println(array[1]);// 30
System.out.println(array[2]);// 10

下面是数组元素赋值的内存示意图:

1. array[0] = 20; 这是一行赋值语句,把数据20赋值给数组的第1个元素,第1个元素就是数组下标为0的元素。赋值之后,元素的值由0变成了20。数组名[索引]可以看成是一个变量。

2. array[2] = 10;这行也是一条赋值语句,把数据10赋值给数组的第3个元素,第3个元素就是数组下标为2的元素。赋值之后,元素的值由0变成了10。数组名[索引]可以看成是一个变量。

3. array[1] = array[0] + array[2]; 这一行仍然是赋值语句,计算array[0] + array[2]的值,将结果赋值给array[1]。即 20 + 10的值30赋值给array[1],赋值之后,元素的值变为30。数组名[索引]可以看成是一个变量。

所以当执行打印语句的时候,打印的结果分别是:20、30、10

System.out.println(array[0]);// 20 
System.out.println(array[1]);// 30
System.out.println(array[2]);// 10

数组和其他局部变量的内存

public static void main(String[] args) {
    int num = 0;
    int sum = 0;
    int[] array = {10,20,30};//new int[]{10,20,30};
    num = array[0] * array[2] / array[1];
    sum = array[0] + array[1] + array[2];
    System.out.println(num);
    System.out.println(sum);
}

局部变量存放在栈区,num、sum、array都是局部变量,因此他们存放在栈区。new开辟的内存在堆区。

下面是定义变量num,sum,array时的内存分配情况:

1. int num = 0; 定义了一个局部变量num,num的初始值是0。局部变量num被存放在了内存 的栈区。如上图所示。

2. int sum = 0;定义了一个局部变量sum,sum的初始值是0。局部变量sum被存放在了内存的 栈区。如图所示。

3. int[] array 定义了一个局部变量array,array的值最终会保存堆区数组的首地址。栈区采用先进后出的方式来管理,即先定义的局部变量在栈底,后定义的局部变量再栈顶。

4. {10, 20, 30}是数组静态初始化的简写模式,完整的写法是 new int[]{10, 20, 30}。new关键字在堆区开辟了12个字节的内存,用于存放3个int数据,数组的首地址是15db9742。

5. 数组一共包含3个int元素,元素的初始值分别是10(array[0])、20(array[1])、30(array[2])。

6. 将数组的首地址15db9742赋值给array变量。即array的值是15db9742。

num = array[0] * array[2] / array[1];
sum = array[0] + array[1] + array[2];
System.out.println(num);
System.out.println(sum);

修改num和sum值的内存图:

1. num = array[0] * array[2] / array[1]; 即 10 * 30 / 20,将结果15赋值给变量num。所以在内存中num的值由0变为了15。

2. sum = array[0] + array[1] + array[2]; 即 10 + 20 + 30,将结果60赋值给变量sum。所以内存中sum的值由0变为了60。

3. 所以打印num和sum的值,分别是15和60。

多个数组内存图

public static void main(String[] args) {
    int[] arr1 = new int[2];
    int[] arr2 = {15, 10, 20};
    System.out.println(arr1);//第一个数组堆区内存地址15db9742
    System.out.println(arr1[0]);// 0
    System.out.println(arr1[1]);// 0
    System.out.println(arr2);//第二个数组堆区内存地址6d06d69c
    System.out.println(arr2[0]);// 15
    System.out.println(arr2[1]);// 10
    System.out.println(arr2[2]);// 20
    arr1[0] = 50;
    arr1[1] = arr1[0] + arr2[0]; //65
    arr2[2] = 28;
    System.out.println(arr1);//第一个数组堆区内存地址15db9742
    System.out.println(arr1[0]);// 50
    System.out.println(arr1[1]);// 65
    System.out.println(arr2);//第二个数组堆区内存地址6d06d69c
    System.out.println(arr2[0]);// 15
    System.out.println(arr2[1]);// 10
    System.out.println(arr2[2]);// 28
}

上述代码的输出结果:

数组arr1、arr2内存分配情况:

对于int[] arr1 = new int[2];可以分解为4个步骤:

1. 定义局部变量arr1,数据类型是 int[],局部变量被存放在了内存的栈区。对应代码:int[] arr1

2. 通过new关键字,在堆区开辟一段连续的内存空间,开辟的空间大小是8个字节。这段内存空间的首地址是15db9742。之所以开辟8个字节,是因为需要存放2个int数据,每个int是4个字节,所以是8个字节。

3. 系统为数组的2个元素设置默认值0。因为是动态初始化,所以系统来设置默认初始值,int类型元素的初始值默认是0。-----步骤2和3对应的代码是: new int[2]

4. 将数组的首地址赋值给变量arr1,因此arr1的值是地址15db9742

对于int[] arr2 = {15, 10, 20};等价于 int[] arr2 = new int[]{15, 10, 20};仍然可以分解为4个步骤:

1. 定义局部变量arr2,数据类型是 int[],局部变量被存放在了内存的栈区。对应代码:int[] arr2

2. 通过new关键字,在堆区开辟一段连续的内存空间,开辟的空间大小是12个字节。这段内存空间的首地址是6d06d69c。之所以开辟12个字节,是因为需要存放3个int数据,每个int是4个字节,所以是12个字节。

3. 为3个数组元素分别赋初始值15,10,20。-----步骤2和3对应的代码是: {15, 10, 20}

4. 将数组的首地址赋值给变量arr2,因此arr2的值是地址6d06d69c

 System.out.println(arr1);//第一个数组堆区内存地址15db9742
 System.out.println(arr1[0]);// 0
 System.out.println(arr1[1]);// 0
 System.out.println(arr2);//第二个数组堆区内存地址6d06d69c
 System.out.println(arr2[0]);// 15
 System.out.println(arr2[1]);// 10
 System.out.println(arr2[2]);// 20

上述7行打印的结果是:

修改数组arr1、arr2元素值:

arr1[0] = 50;
arr1[1] = arr1[0] + arr2[0]; //65
arr2[2] = 28;

修改数组元素的内存图如下:

1. arr1[0] = 50; 这行代码的作用是给arr1下标为0的元素(即arr1的第1个元素)赋值,将arr1[0]的值修改成50。

2. arr1[1] = arr1[0] + arr2[0]; 这行代码的作用是给arr1下标为1的元素(即arr1的第2个元素)赋值,将arr1[1]的值修改成65(即 50 + 15)。

3. arr2[2] = 28;这行代码的作用是给arr2下标为2的元素(即arr2的第3个元素)赋值,将arr2[2]的值修改成28。

System.out.println(arr1);//第一个数组堆区内存地址15db9742
System.out.println(arr1[0]);// 50
System.out.println(arr1[1]);// 65
System.out.println(arr2);//第二个数组堆区内存地址6d06d69c
System.out.println(arr2[0]);// 15
System.out.println(arr2[1]);// 10
System.out.println(arr2[2]);// 28

上述7行打印的结果是:

多个数组变量指向相同堆区内存

public static void main(String[] args) {
    int[] arr1 = {25, 13, 36};
    int[] arr2 = arr1;//将arr1的值赋值给arr2,即arr2和arr1保存了相同的堆区地址。
    System.out.println(arr1);// arr1保存的内存地址是15db9742
    System.out.println(arr2);// arr2保存的内存地址是15db9742
    System.out.println(arr1[0]);// 25
    System.out.println(arr2[0]);// 25
    System.out.println(arr1[1]);// 13
    System.out.println(arr2[1]);// 13
    arr1[0] = 100;
    arr2[1] = 200;
    System.out.println(arr1);// arr1保存的内存地址是15db9742
    System.out.println(arr2);// arr2保存的内存地址是15db9742
    System.out.println(arr1[0]);// 100
    System.out.println(arr2[0]);// 100
    System.out.println(arr1[1]);// 200
    System.out.println(arr2[1]);// 200
}

上述代码输出的结果:

数组arr1、arr2内存分配情况:

int[] arr1 = {25, 13, 36};的完整格式是: int[] arr1 = new int[]{25, 13, 36};这行代码可以分为4个步骤:

1. 定义局部变量arr1,数据类型是 int[],局部变量被存放在了内存的栈区。对应代码:int[] arr1

2. 通过new关键字,在堆区开辟一段连续的内存空间,开辟的空间大小是12个字节。这段内存空间的首地址是15db9742。之所以开辟12个字节,是因为需要存放3个int数据,每个int是4个字节,所以是12个字节。

3. 为3个数组元素分别赋初始值25,13,36。-----步骤2和3对应的代码是: {25, 13, 36}

4. 将数组的首地址赋值给变量arr1,因此arr1的值是地址15db9742

int[] arr2 = arr1; 这是一行赋值语句。这行代码可以分为2个步骤:

1. 定义局部变量arr2,数据类型是int[],局部变量存放在了内存的栈区。对应代码:int[] arr2

2. 将变量arr1的值赋值给变量arr2。因为arr1里存放的是堆区地址15db9742,因此赋值以后,arr2的值也是15db9742。相当于有2个数组变量指向了同一块内存区域。所以无论通过arr1访问数组元素还是通过arr2访问数组元素都会得到相同的数据。

System.out.println(arr1);// arr1保存的内存地址是15db9742
System.out.println(arr2);// arr2保存的内存地址是15db9742
System.out.println(arr1[0]);// 25
System.out.println(arr2[0]);// 25
System.out.println(arr1[1]);// 13
System.out.println(arr2[1]);// 13

上述6行代码打印的结果如下:

修改数组元素值的内存图如下:

1. arr1[0] = 100; 通过数组arr1修改了堆区内存中的数据。因为arr2和arr1指向的是相同的内存 区域,所以arr2[0]的值也是100。

2. arr2[1] = 200; 通过数组arr2修改了堆区内存中的数据。因为arr1和arr2指向的是相同的内存 区域,所以arr1[1]的值也是200。

System.out.println(arr1);// arr1保存的内存地址是15db9742
System.out.println(arr2);// arr2保存的内存地址是15db9742
System.out.println(arr1[0]);// 100
System.out.println(arr2[0]);// 100
System.out.println(arr1[1]);// 200
System.out.println(arr2[1]);// 200

上述6行代码打印的结果如下:

数组内存的总结

1. 数组变量存放的是堆区的数组的首地址。数组变量本身存放在栈区,它的值是堆区的地址。

2. 数组元素存放在堆区,通过 数组名[索引]的方式可以访问数组元素。

3. 给数组变量赋值,相当于改变了数组变量的指向。

4. 如果多个数组变量指向了同一个数组,可以通过任意一个数组变量修改数组元素的值。

数组操作的注意事项

数组下标越界

数组下标越界:指的是数组下标的值超出了下标的取值范围。

数组下标的取值范围:0 ~ 数组个数 - 1

例如:

int[] arr = new int[3];
System.out.println(arr);
System.out.println(arr[3]);//此处会产生数组越界问题。数组下标的取值范围是[0, 2],但访问了下标为3的元素。

上面代码运行后,报出了一个异常(Exception),异常的意思是数组的索引超出了边界。下标3超出了下标的范围。简单说就是数组的下标越界。

int[] arr = new int[3]; 可以分解为4个步骤:

1. 定义局部变量arr,数据类型是 int[],局部变量被存放在了内存的栈区。对应代码:int[] arr

2. 通过new关键字,在堆区开辟一段连续的内存空间,开辟的空间大小是12个字节。这段内存空间的首地址是15db9742。之所以开辟12个字节,是因为需要存放3个int数据,每个int是4个字节,所以是12个字节。

3. 系统为数组的3个元素设置默认值0。因为是动态初始化,所以系统来设置默认初始值,int类型元素的初始值默认是0。-----步骤2和3对应的代码是: new int[3]

4. 将数组的首地址赋值给变量arr,因此arr的值是地址15db9742

System.out.println(arr[3]); 这行代码的作用是打印数组下标为3的元素的值,通过上面的图,我们会发现,数组只有3个元素,对应的下标分别是0,1,2。现在要访问下标为3的元素,3超出了数组下标的范围,所以程序会出现异常。开发中应避免出现数组越界的问题。

空指针异常

null是一个常量,用于给引用类型变量赋值。

空指针异常:指的是数组(或对象)指向了一个空地址,如果指向了空地址以后,还在继续访问数据,就会出现空指针异常。

public static void main(String[] args) {
    int[] arr = new int[3];
    System.out.println(arr);// arr的值是15db9742
    arr = null;// 将arr设置为null,即空值(内存地址为0的值)
    System.out.println(arr);//  null
    System.out.println(arr[0]); //空指针异常
}

上面代码运行的结果是:

图中报出了一个异常,异常的意思是空指针异常。出现这种问题的原因就是,数组变量保存的地址已经被清空,数组已不再指向以前的堆区,所以访问数据的时候,就会出现异常。

int[] arr = new int[3]; 可以分解为4个步骤:

1. 定义局部变量arr,数据类型是 int[],局部变量被存放在了内存的栈区。对应代码:int[] arr

2. 通过new关键字,在堆区开辟一段连续的内存空间,开辟的空间大小是12个字节。这段内存空间的首地址是15db9742。之所以开辟12个字节,是因为需要存放3个int数据,每个int是4个字节,所以是12个字节。

3. 系统为数组的3个元素设置默认值0。因为是动态初始化,所以系统来设置默认初始值,int类型元素的初始值默认是0。-----步骤2和3对应的代码是: new int[3]

4. 将数组的首地址赋值给变量arr,因此arr的值是地址15db9742

1. arr = null; 执行之后,arr中原有的值15db9742被清空。无法再指向堆区的数组元素。

2. System.out.println(arr[0]); 这行代码中的 arr[0]出现了异常,原因就是arr已经不再指向任何(有效的)内存地址,所以操作数据的时候,会出现空指针异常。

数组的遍历

什么是数组遍历

数组的遍历:指的是获取数组中的每个元素。

public static void main(String[] args) {
    int[] arr = {10, 20, 30, 40, 50};
    System.out.println(arr[0]);
    System.out.println(arr[1]);
    System.out.println(arr[2]);
    System.out.println(arr[3]);
    System.out.println(arr[4]);
}

上述代码的作用就是遍历并打印每个数组元素的值。这段代码虽然能达到遍历的效果,但是代码质量不高,如果数组有100万条数据,输出语句需要写100万行。

通过观察上述代码,你会发现明显的规律:每条打印语句唯一的区别就是数组的下标不同。下标从0开始,每次下标增1,直到数组个数-1。因此可以使用for循环对数组进行遍历。

public static void main(String[] args) {
    int[] arr = {10, 20, 30, 40, 50};
    for(int i = 0; i < 5; i++) {
        System.out.println(arr[i]);
    }
}

上面的代码就是简化之后的数组遍历代码。仔细观察不难发现,i 的初始值 0,可以对应数组第 1 个元素的下标0,每循环一次,执行一次 i++, 可以让 i 的值增 1,这样能对应数组的每一个下标。直到 i 的值达到数组元素个数-1,即 i < 数组元素个数

数组元素个数

因为数组元素个数很重要,所以Java提供了获取数组元素个数的的方式。

格式:数组名.length

示例:arr.length

鉴于此,上述代码可以进一步优化。

public static void main(String[] args) {
    int[] arr = {10, 20, 30, 40, 50};
    for(int i = 0; i < arr.length; i++) {
        System.out.println(arr[i]);
    }
}

数组遍历的通用格式

因为每个数组的元素个数,都可以通过数组名.length获得,所以任意一个数组的遍历都可以写成如下形式

public static void main(String[] args) {
    int[] 数组名 = {...};
    for(int i = 0; i < 数组名.length; i++) {
        数组名[i];//对 数组名[i] 进行操作
    }
}

数组遍历示例

public static void main(String[] args) {
    int[] arr = {111, 222, 333, 444};
    //数组arr的遍历
    for(int i = 0; i < arr.length; i++) {
        System.out.println(arr[i]);
    }

    int[] arr2 = {35, 12, 16, 24, 76, 88, 31};
    //数组arr2的遍历
    for(int i = 0; i < arr2.length; i++) {
        System.out.println(arr2[i]);
    }
}

数组的常用操作

数组求最值

1. 需求:有一组数据 10,8,23,41,52,66,34,12。编写代码求出数组中的最大值。

2. 代码:

public static void main(String[] args) {
    //需求:有一组数据 10,8,23,41,52,66,34,12。
    //编写代码求出数组中的最大值。
    //分析:
    //1. 这组数据使用 int 数组来保存。---数组的定义、数组的静态初始化。
    //2. 定义一个变量 max,用于保存数组中最大的元素。
    //3. 遍历数组,让 max 依次和数组中的每个元素比较,如果元素大于max,将max值更新为元素的值。
    //4. 一趟循环结束后,max中保存的就是数组中的最大值。
    int[] array = {10, 8, 23, 41, 52, 66, 34, 12};
    int max = 0;
    for (int i = 0; i < array.length; i++) {
        if (array[i] > max) {
            max = array[i];
        }
    }
    System.out.println("max = " + max);
}

数组元素求和、平均值

1. 需求:有一个具有5个 int 数据的数组,数组中的每个元素都是[10, 30]之间的随机数。编写代码求出数组中的元素的和以及元素的平均值,打印出所有高于平均值的数,打印出所有低于平均值的数。

2. 代码:

public static void main(String[] args) {
    //需求:有一个具有5个 int 数据的数组,数组中的每个元素都是[10, 30]之间的随机数。
    //编写代码求出数组中的元素的和以及元素的平均值,打印出所有高于平均值的数,打印出所有低于平均值的数。
    //分析:
    //1. 定义一个数组,使用动态初始化为数组赋初始值。
    //2. 定义一个变量sum保存元素的和,定义一个变量avg保存数组元素的平均值---平均值变量使用double类型。
    //3. 通过循环为每个元素赋值,数组元素的值在[10,30]之间。---循环之前先创建Random对象。
    //4. 在循环的过程中,计算元素的和。
    //5. 循环结束后,计算元素的平均值。
    //6. 遍历数组,打印所有大于平均数的数组元素。
    //7. 遍历数组,打印所有小于平均数的数组元素。

    int[] array = new int[5];
    int sum = 0;
    double avg = 0.0;
    Random random = new Random();
    for(int i = 0; i < array.length; i++) {
        array[i] = random.nextInt(30 - 10 + 1) + 10;
        System.out.print(array[i] + " ");
        sum += array[i];
    }
    System.out.println();
    avg = sum * 1.0 / array.length;
    System.out.println("sum = " + sum + ", avg = " + avg);

    System.out.print("比平均数大的数是:");
    for(int i = 0; i < array.length; i++) {
        if(array[i] > avg) {
            System.out.print(array[i] + " ");
        }
    }
    System.out.println();

    System.out.print("比平均数小的数是:");
    for(int i = 0; i < array.length; i++) {
        if(array[i] < avg) {
            System.out.print(array[i] + " ");
        }
    }
    System.out.println();
}

查找数组元素

1. 需求:有一个包含10个元素的数组,每个元素的值在[10,30]之间,查找数组中是否包含18,如果有18,打印出值为18的元素的下标。如果没有18,打印“数组中不包含18”。

2. 代码:

public static void main(String[] args) {
    //需求:有一个包含10个元素的数组,每个元素的值在[10,30]之间,
    //查找数组中是否包含18,如果有18,打印出值为18的元素的下标。如果没有18,打印“数组中不包含18”。
    //分析:
    //1. 定义一个int数组,使用动态初始化为数组赋初始值。
    //2. 创建Random对象
    //3. 通过循环为每个数组元素赋值
    //4. 定义一个boolean类型变量isContain,初始值设置为false,用于记录数组是否包含18,如果包含18,变量值设置为true。
    //5. 遍历数组中的元素,判断是否包含18,如果包含18,将isContain设置为true,并结束循环。
    //6. 如果遍历数组后,isContain仍然为false,表示数组中不包含18.
    int[] array = new int[10];
    Random random = new Random();
    for(int i = 0; i < array.length; i++) {
        array[i] = random.nextInt(30 - 10 + 1) + 10;
        System.out.print(array[i] + " ");
    }
    System.out.println();
    boolean isContain = false;
    for(int i = 0; i < array.length; i++) {
        if(array[i] == 18) {
            isContain = true;
            break;
        }
    }

    if(isContain == false) {
        System.out.println("数组中不包含18.");
    }else {
        System.out.print("数组中包含18。值为18的元素的下标是:");
        for(int i = 0; i < array.length; i++) {
            if(array[i] == 18) {
                System.out.print(i + " ");
            }
        }
    }
}

3. 需求:有一组已经排好顺序的数据:5,13,19,21,37,56,64,75,80,88,92。编写代码查询数组中是否包含数据78,21,13。

4. 代码:(折半查找方式)

折半查找也叫二分查找。它是一种效率较高的查找方法。但是折半查找要求数据必须有序(升序或者降序)。

折半查找的思想:

定义3个变量分别保存第一个元素(low),最后一个元素(high)以及中间元素的下标(mid),mid = (low + high) / 2。

判断中间元素是否是目标数据,如果是目标数据,表示找到数据;

如果中间元素大于目标数据,说明目标数据在第一个元素和中间元素之间。将high改为mid - 1,更新mid的值(mid = (low + high) / 2);

如果中间元素小于目标数据,说明目标数据在中间元素和最后一个元素之间。将low改为mid + 1,更新mid的值(mid = (low + high) / 2);

继续判断中间元素是否是目标数据,如果是目标数据,表示找到数据;

如果中间元素大于目标数据,说明目标数据在第一个元素和中间元素之间。将high改为mid - 1,更新mid的值(mid = (low + high) / 2);

如果中间元素小于目标数据,说明目标数据在中间元素和最后一个元素之间。将low改为mid + 1,更新mid的值(mid = (low + high) / 2);

重复上述步骤,直到 low > high为止。(或者中间找到了数据)

以查找数据21(目标数据)为例,折半查找的过程如下:

目标数据21和中间数据56相比,由于 56 > 21,所以将high改为mid - 1,mid改为(low + high)/ 2

目标数据21和中间数据19相比,由于19 < 21,所以将low改为mid + 1,mid改为(low + high) / 2

目标数据21和中间数据21相比,数据相等,结束查找。

public static void main(String[] args) {
    //需求:有一组已经排好顺序的数据:5,13,19,21,37,56,64,75,80,88,92。
//编写代码查询数组中是否包含数据78,21,13。
//方法二:折半查找方式
    int[] array = {5, 13, 19, 21, 37, 56, 64, 75, 80, 88, 92};
    int num = 21;
    boolean isContain = false;
    int low = 0;
    int high = array.length - 1;
    int mid = (low + high) / 2;
    while(low <= high) {
        if(array[mid] == num) {
            isContain = true;
            break;
        }else if(array[mid] > num) {
            high = mid - 1;
            mid = (low + high) / 2;
        }else {
            low = mid + 1;
            mid = (low + high) / 2;
        }
    }
    if(isContain == true) {
        System.out.println("查到了数据:" + num);
    }else {
        System.out.println("数组中没有数据:" + num);
    }
}

数组的拷贝

数组的拷贝,涉及到2个数组,一个是源数组,一个是目的数组,将源数组的数据拷贝到目的数组中。目的数组的容量(数组长度)要大于等于源数组的容量。所谓的拷贝,就是把源数组下标为0的元素赋值给目的数组下标为0的元素,把源数组下标为1的元素赋值给目的数组下标为1的元素,....,把源数组下标为length-1的元素赋值给目的数组下标为length-1的元素

1. 需求:创建一个包含10个随机数的数组(源数组),随机数的取值范围是[10, 80],将数组中的数据拷贝到一个新的数组中。

2. 代码:

public static void main(String[] args) {
    //需求:创建一个包含10个随机数的数组(源数组),随机数的取值范围是[10, 80],
    //将数组中的数据拷贝到一个新的数组中。
    //分析:
    //1. 创建2个数组,一个数组用于保存10个随机数,另外一个数组用于保存拷贝后的数据,--数组的定义,动态初始化
    //2. 创建Random对象
    //3. 通过循环产生10个随机数,并输出10个数的值
    //4. 编写循环实现拷贝
    //5. 打印拷贝结果
    int[] sourceArray = new int[10];
    int[] destinationArray = new int[sourceArray.length];
    Random random = new Random();
    for(int i = 0; i < sourceArray.length; i++) {
        sourceArray[i] = random.nextInt(80 - 10 + 1) + 10;
        System.out.print(sourceArray[i] + " ");
    }
    System.out.println();
    //实现拷贝
    for(int i = 0; i < sourceArray.length; i++) {
        destinationArray[i] = sourceArray[i];
    }
    //打印拷贝结果
    for(int i = 0; i < destinationArray.length; i++) {
        System.out.print(destinationArray[i] + " ");
    }
    System.out.println();
}

常用

1. 数组是一个容器,用于存储数据。数组在创建的时候要确定容量,数组内部的元素类型必须相同。

2. 数组的长度:数组名.length

3. 数组可以动态初始化,也可以静态初始化。

4. 数组通常和循环结合使用。

5. 数组元素的访问:数组名[下标] -----几维数组就要有几个下标。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值