AP计算机科学A复习:Unit 6 – Array 数组

Unit 6 – Array 数组

每个变量都可以存储一个数据,但如果要处理大量具有相同性质的数据的时候仍然为每个数据都创建单独的变量就很麻烦。

在这类情况下,创建一个「数组」就可以很方便的存取大量的数据。「数组」只需要声明一次,也就是只需创建一个独立的变量,就可以给这些数据提供各自的存储位置,且每个数据都可以被单独访问、修改。

因此,这个单元主要需要了解的就是声明数组、操作数组的语法。

U6.1 Array Creation and Access 读写数组

首先我们要了解的是创建数组的语法。我们已经了解到数组可以存储大量具有相同性质的数据,理所当然的,这些数据都有相同的类型,比如整数、浮点数(小数)、或者字符串等等;此外,我们还需要在创建数组之初就确定好提供的存储位置的数量,这个数量在数组被创建后不能被修改。看这段代码:

		int[] a = {65, 98, 76, 92, 79};

这就是一句创建数组的代码。在赋值符号「=」的两侧分别有三个部分:左侧是要创建的数组的数据类型紧跟一个中括号 [ ] ,这决定了数组有能力存储什么样类型的数据,中括号是区别普通变量和数组的标志;随后的「 a 」是数组的变量名,当然你可以自己起一个其他的变量名;

右侧是用 { } 包裹起来的五个数据,数据之间使用「, 」分隔。这个大括号里有多少个数据,数组就提供多少个存储位置。每个存储位置都有自己的编号,可以类比为一个数轴上每个整数都有自己的位置,以这里的 5 个数据为例:

数组的存储位置被从左往右,从 0 开始编号。因此第一个数据 65 所在位置的编号就是 0 ,以此类推,到最后一个数据 79 ,则它所在位置的编号是 4 。

对这个数组来说,各个位置上存储的的数据可以被改变,但是位置本身就像一个容器,一直对应着它固定的编号。所以我们可以通过位置的编号来读写数据:

		int[] a = {65, 98, 76, 92, 79};
		a[3] = 100;
		System.out.print(a[0] +"\n" + a[1]+ "\n" + a[2] +"\n" + a[3] +"\n" + a[4]);

在创建数组并赋初值之后,我在第二句话访问了编号为 3 的存储位置,把它存储的数据修改为 100 ,除了要加上中括号 [ ] 并在中括号里面写上存储位置的编号以外,和一般的变量赋值没有区别。

最后使用输出语句分别输出了 0 – 4 号位置的内容。「”\n”」代表的是换行,因此最后就输出了:

65

98

76

100

79

注意,如果访问到不存在的位置,程序就会报错。比如这里只有 0 – 4 号位置,并没有 5 号位置,如果访问 a [5] 就会得到:

刚才我们在创建数组的时候就确定了数组里面要存放的数据,但如果开始的时候并不知道这些数据或者不想在创建数组的时候就给它赋值,就需要使用 「new keyword 」来创建数组:

		int[] b = new int[5];

使用 new keyword 创建数组的语句和刚才赋了初值的写法差不多。左侧是一样的,包括数据类型、中括号、还有数组名;右侧则有一点区别,使用 「new」开头,再加上跟有中括号的数据类型,注意右侧的中括号里要写上这个数组拥有的存储位置的数量。

这样我们就创建了一个不需要赋初值的数组。所有的存储位置会先由默认值占位,比如 int 类型的数组默认所有的存储位置都存 0; double 的默认值是 0.0;boolean 的默认值是 false;所有的 reference type 数组的默认值都是 null。

注意,上面我写的语句的含义是「新建一个有五个存储位置的数组」。虽然字面上写的是「5」,但是存储位置的编号依然是从0 开始直到 4。

U6.2 Traversing Arrays 遍历数组

你已经了解了创建数组的语法。现在要介绍的是如何访问或者修改数组里存储的数据。因为数组一般被用来处理大量的数据,所以不适合对每一个存储位置上的数据单独写输出语句或者赋值语句等。否则工作量会异常的大。

「Traversing Arrays」指的就是利用循环语句访问数组里的每一个数据,这样就可以高效的操作数组。

循环语句本身有计数器变量,比如常用的 「 i 」从 0 开始每次循环递增 1 直到循环条件不再被满足;而数组的每个存储位置又有自己的编号,就恰好可以利用 i 在这里每次循环递增 1 的特性来访问数组的各个存储位置:

我创建了一个名叫「 c 」的数组。这个数组有 5 个存储位置,根据上一个小节了解的规则,第一个存储空间的编号为 0 ,第二个存储空间的编号为 1;……;第五个存储空间的编号为 4。因此,循环的计数器变量应该从0开始,这样就让输出语句第一次输出的数据是第一个存储空间存储的数据「82」。然后依次循环,每次计数器递增 1,一旦计数器变量大于 4 就停止循环。总共循环了 5 圈,挨个访问输出了数组 c 里的每一个数据。

要注意的是,在定义 for 循环的循环条件时,我使用了「 c.length – 1」这个表达式来得到计数变量的上限,也就是循环的终止条件。「 c.length 」代表的是数组所有存储位置的总计数量,这里就是 5 。但是计数器变量从 0 开始计数,同时也代表了存储位置的编号,最后一个数值的编号就应该是 4,和总计数量差1,因此要把「c.length」再减去 1 。最后就可以访问到并且输出每一个存储位置里面的数据,完成「Traversing Arrays」。

U6.3 Enhanced for Loop for Arrays 

除了使用寻常的 for 循环来访问数组里面存储的大量的数据,还有一种简化的 for 循环写法:「 Enhanced for Loop」。这种写法不需要手动定义计数器变量和设置循环条件等,更加便利,但是功能也不如传统的 for 语句丰富。这样写:

		int[] d = {82, 91, 92, 67, 97};
		

		for(int element : d) {
			System.out.println(element);
		}

可以看到,这段代码中有一个数组 「d」。随后我使用了一个 Enhanced for Loop。与一般的 for 循环有差别的地方是 for 关键词后面紧跟的小括号里面的内容。在这里我们只需要完成输入两个内容,使用冒号隔开。

第一个内容是定义一个 local variable,写在冒号的左侧,这个 local variable 的数据类型和要访问的数组必须兼容。例如,数组的数据类型是 int,那么这个 local variable 的数据类型最好就是 int,如果强行设置成 double 也不是不行,但要是设置成 String 程序就不能正常编译。这是因为,在循环的过程中,这个 local variable 在循环的每一圈都按照数组的存储位置编号的顺序来存入一个数据。

第二个内容在冒号的右侧,是要访问的数组的名称。

这是上面这段程序的输出结果:

82

91

92

67

97

你可以看出,在第一圈循环的时候,local variable 读入了第 0 个位置上的数据;……;以此类推,每一圈循环都自动按顺序读入这个数组里的下一个位置上的数据。这样也可以成功的访问数组里大量的数据。

但要注意的是,修改这里的 local variable 的值并不影响数组本身的数据。因为 local variable 只是复制并存储了数组里的某一个数据,这个变量本身是独立于数组存在的。

U6.4 Developing Algorithms Using Arrays 数组内数据的操作

目前为止你已经了解了数组的基本写法。所以就可以尝试对数组里的数据进行一些简单的处理,我们分成不同的、具体的目的来讨论,用来达到这些目的所写作的代码、思考的逻辑、数学的计算等一系列手段被称为「算法 Algorithms」。

找最大(最小)值

首先我们来找出一个数组里最大的数。基本的逻辑是,使用一个临时的变量存储数组的首个数据,然后在循环过程中挨个和后面的数据对比,一旦遇到更大的数据就丢弃原来的数据转而在这个临时变量中存储当前遇到的这个最大数。这样,在循环结束后就可以得到整个数组里最大的数据。反之,寻找数组里的最小数也可以使用这个算法。我用找最大数来举例:

		int[] d = {82, 91, 100, 67, 97};
		int temp = d[0];

		for(int element : d) {
			if(temp < element) {
				temp = element;
			}
			System.out.println(element);
		}
		
		System.out.println("最大值是:"+temp);
	}

可以看到,我声明了一个名叫 temp 的变量用来存储暂时遇到的最大的数,循环中如果遇到更大的数据就会替代 temp 里原有的数据。因此最后会输出「最大值是:100」。

尝试一下自己写作「找最小数」的程序。

求和、平均数

求和本身就是计算平均数的前置任务,所以就放在一起了。求和非常简单,只需要单独声明一个变量,然后在循环过程中把数组的每一个数据累加即可。而计算平均数则只需要再把数据的除以数据的数量。这样写:

	public static void main (String[] args) {
		int[] e = {82, 37, 71, 91, 97, 62};
		int sum = 0;
		
		for (int i = 0; i <= e.length-1 ; i++) {
			sum += e[i];//累加求和
		}
		
		double average = (double)sum / e.length ;//计算平均数
		
		System.out.println("和是:"+ sum);
		System.out.println("平均数是"+ average);
	}

以上代码中,我先使用循环访问了数组 e 的每一个数据并把它们累加得到。然后把累加所得总和除 e 的数据个数,得到平均数

有一个细节是,计算平均数的算式里,所有的变量都是整数,因此电脑会得到一个整数类型的结果,这样一来遇到有小数部分的运算结果就会被丢掉小数部分的数据,这是 java 语言本身的特性导致的。而平均数恰好常常出现小数的情况,所以,一定要记得把算式中的某个数据强制转换成 double ,并且把最终的结果存储在 double 类型的变量。这样才可以得到正确的平均数的值。

是否重复出现的数

要判断是否有重复出现的数,我们需要使用一个循环来遍历数组 e。

在每一圈循环中都要判断当前的数据是否和数组中任何其他的数据吻合,如果是,则使用一个 boolean 变量记录下「 true 有重复」;如果不是,则用这个 boolean 变量记录下「false 无重复」。因此,双层循环嵌套是合适的选择:

		int[] e = {82, 37, 71, 82, 97, 62};
		boolean hasDublication = false;
		
		for (int i = 0; i <= e.length - 1; i++) {
			for(int j = i+1 ; j <= e.length - 1; j++) {
				if (e[i] == e[j]) {
					hasDublication = true;
				}
			}
		}
		
		System.out.println("有无重复" + hasDublication);

这样,所有的数据都被互相对比过恰好一次,既没有重复对比,也没有遗漏任何的组合。一旦发现任何两个数据相同,则 hasDublication 变量就会被赋值为真,表示有重复数据出现;反之则没有重复数据出现。

改变数据的顺序

例如,我们把数组里的数据向右平移一个存储位置,达到这样的效果:

首先需要创建一个拥有相同存储位置数量的数组,这里把它命名为 g,然后把原数组的最后一个数据存储到 g 的首个存储位置。接着,从 g 的第二个位置开始挨个读入原数组除了最后一个数据的其他所有数据:

		int[] f = {100, 37, 71, 82, 97};
		int[] g = new int[f.length];
		
		g[0] = f[f.length -1];// 原数组f的最后一个数据存到 g 的首位
		
		for (int i = 1; i <= f.length-1 ; i++) {
			g[i] = f[i-1]; //在 g 数组接着挨个存入 f 剩下的数据
		}
		
		for (int a: g) { //输出检查
			System.out.println(a);
		}

这样就把数据都移动到了自己右侧的存储位置上。

总结

到这里就已经介绍了 Array 的基本语法和简单的算法应用。你可以在自己的程序中使用数组并搜索极值、找到你需要的数据等等。

练习

2008-1

2009-3

by Oscar.L
E-mail [email protected]

Comments

  1. 1
    Windows Edge
    1 year ago
    2023-1-08 20:08:14

Send Comment Edit Comment

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
Previous
Next