|
教学目标: i掌握数组的声明和创建 i掌握数组初始化 i掌握数组元素的访问 i掌握多维数组 i掌握数组的复制 i掌握基本的排序算法和数组的排序
|
一、数组的声明和创建
1.数组是什么?
数组是由相同类型的若干项数据组成的一个数据集合。也就是说数组是用来集合相同类型的对象并通过一个名称来引用这个集合,数组是引用类型。
2.数组的声明
你可以声明任何类型的数组──原始类型或引用类型:
char s[];
Point p[]; // 这里Point是一个类
在Java编程语言中,即使数组是由原始类型构成,甚或带有其它引用类型,数组也是一个对象。声明不能创建对象本身,而申请得到的是一个引用,该引用可被用来存放数组对象的首地址。数组元素使用的实际内存可由new语句或数组初始化软件动态分配。在后面,你将看到如何创建和初始化实际数组。
上述这种将方括号置于变量名之后的声明数组的格式,是用于C、C++和Java编程语言的标准格式。这种格式会使声明的格式复杂难懂,因而,Java编程语言允许一种替代的格式,该格式中的方括号位于变量名的左边:
char[] s;
Point[] p;
这样的结果是,你可以认为类型部分在左,而变量名在右。上述两种格式并存,你可选择一种你习惯的方式。声明不指出数组的实际大小。
注意:当数组声明的方括号在左边时,该方括号可应用于所有位于其右的变量
3.数组的创建
可以象创建对象一样,使用关键字new 创建一个数组。创建的时候要指明数组的长度。
s = new char [20];
p = new Point [100];
第一行创建了一个20个char值的数组,第二行创建了一个100个类型Point的变量。然而,它并不创建100个Point对象;创建100个对象的工作必须分别完成如下:
p[0] = new Point();
p[1] = new Point();
·
·
·
用来指示单个数组元素的下标必须总是从0开始,并保持在合法范围之内--大于0或等于0并小于数组长度。任何访问在上述界限之外的数组元素的企图都会引起运行时出错。
数组的下标也称为数组的索引,必须是整数或者整数表达式,如下:
int i[] = new int[(9-2)*3];//这是合法的
其实,声明和创建可以定义到一行,而不用分开写。
二、数组的初始化
当创建一个数组时,每个元素都被自动使用默认值进行初始化。在上述char数组s的例子中,每个值都被初始化为0 (\u0000-null)字符;在数组p的例子中, 每个值都被初始化为null,表明它还未引用一个Point对象。在经过赋值 p[0] = new Point()之后,数组的第一个元素引用为实际Point对象。
注意:所有变量的初始化(包括数组元素)是保证系统安全的基础,变量绝不能在未初始化状态使用。
Java编程语言允许使用下列形式快速创建数组,直接定义并初始化:
String names [] = {
“Georgianna”,
“Jen”,
“Simon”,
};
其结果与下列代码等同:
String names [] ;
names = new String [3];
names [0] = “Georgianna”;
names [1] = “Jen”;
names [2] = “Simon”;
这种”速记”法可用在任何元素类型。例如:
Myclass array [] = {
new Myclass (),
new Myclass (),
new Myclass ()
};
适当的类类型的常数值也可被使用:
import java.awt.Color;
Color palette [] = {
Color.blue,
Color.red,
Color.white
};
1.数组的内存分配
数组一旦被创建,在内存里面占用连续的内存地址。
数组还具有一个非常重要的特点——数组的静态性:数组一旦被创建,就不能更改数组的长度。
比如,定义数组如下: Point[] p = new Point [3];
其中p是数组名,数组长度是3,数组在被创建的时候,内存示意图如下:
三、数组元素的访问
在Java编程语言中,所有数组的下标都从0开始。 一个数组中元素的数量被作为具有length属性的部分数组对象而存储; 这个值被用来检查所有运行时访问的界限。如果发生了一个越出界限的访问,那么运行时的报错也就出现了。
使用length属性的例子如下:
int list [] = new int [10];
for (int i= 0; i< list.length; i++){
System.out.println(list[i]);
}
使用length属性使得程序的维护变得更简单。
所有元素的访问就通过数组的下标来访问,如上例的list[i],随着i的值发生变化,就依次访问list[0]、list[1]、list[2]…
如果想要给某个数组元素赋值,如下方式: list[0]=5; list[1]=6;…
示例:假如定义一个数组:int c [] = new int[12];
……//进行赋值的语句
|
变量c |
|
101 102 103 -123 321 456 654 236 7 2 9 109 |
|
c[0] |
|
c[1] |
|
c[2] |
|
c[3] |
|
c[4] |
|
c[5] |
|
c[6] |
|
c[7] |
|
c[8] |
|
c[9] |
|
c[10] |
|
c[11] |
然后就可以根据数组名[下标]来取值了。
如:int a = c[3];
结果就是:从数组中取出下标为3的元素的值“-123”,然后赋值给a。
3.1 更优化的for循环语句
在访问数组的时候,经常使用for循环语句。从JDK5.0开始,提供了一个更好的for循环语句的写法,示例如下:
public class Test {
public static void main(String args[]) {
int a[] = new int[3];
//旧的写法,赋值
for(int i=0; i a[i] = i; } //新的写法,取值 (注意:新的简易for只能用于取值,不能用于赋值) for(int m : a){ System.out.println(m); } } } 显然JDK5.0版本以后for的简易写法比以前的是大大简化了。 四、多维数组 1.多维数组的基础知识 Java编程语言没有象其它语言那样提供多维数组。因为一个数组可被声明为具有任何基础类型,所以你可以创建数组的数组(和数组的数组的数组,等等)。一个二维数组如下例所示: int twoDim [][] = new int [4][]; twoDim[0] = new int[5]; twoDim[1] = new int[5]; 首次调用new而创建的对象是一个数组,它包含4个元素,每个元素对类型array of int的元素都是一个null引用并且必须将数组的每个点分别初始化。 因为这种对每个元素的分别初始化,所以有可能创建非矩形数组的数组。也就是说,twoDim的元素可按如下方式初始化: twoDim[0] = new int [2] twoDim[1] = new int [4]; twoDim[2] = new int [6]; twoDim[3] = new int [8]; 由于此种初始化的方法烦琐乏味,而且矩形数组的数组是最通用的形式,因而产生了一种”速记”方法来创建二维数组。例如: int twoDim [][] = new int [3][4]; 可被用来创建一个每个数组有4个整数类型的3个数组的数组。 对二维数组 int [][] a = new int[3][4]; 可以理解成为如下图所示: a[ 0 ][ 0 ] a[ 1 ][ 0 ] a[ 2 ][ 0 ] a[ 0 ][ 1 ] a[ 1 ][ 1 ] a[ 2 ][ 1 ] a[ 0 ][ 2 ] a[ 1 ][ 2 ] a[ 2 ][ 2 ] a[ 0 ][ 3 ] a[ 1 ][ 3 ] a[ 2 ][ 3 ] 行的下标值 列的下标值 注意:尽管声明的格式允许方括号在变量名左边或者右边,但此种灵活性不适用于数组句法的其它方面。例如: new int [][4]是非法的。 2.示例 class FillArray { public static void main (String args[]) { int[ ][ ] matrix = new int[4][5]; //二维数组的声明和创建 for (int row=0; row < 4; row++) { for (int col=0; col < 5; col++) { matrix[row][col] = row + col; //二维数组的访问,为元素赋值 } } } } 当然也可以直接定义并赋值,如下: double[ ][ ] c = { {1.0, 2.0, 3.0, 4.0}, {0.0, 1.0, 0.0, 0.0}, {0.0, 0.0, 1.0, 0.0} }; 从上面可以看得很清楚,二维数组其实就是一维的一维数组。 3.多维数组的本质 N维数组就是一维的N-1维数组,比如:三维数组就是一维的二维数组。 三维以至多维数组都是一个思路,一维数组——〉二维数组——〉三维数组 的实例: class Fill3DArray { public static void main (String args[]) { int[ ][ ][ ] M = new int[4][5][3]; for (int row=0; row < 4; row++) { for (int col=0; col < 5; col++) { for (int ver=0; ver < 3; ver++) { M[row][col][ver] = row + col + ver; } } } } } 五、数组的复制 数组一旦创建后,其大小不可调整。然而,你可使用相同的引用变量来引用一个全新的数组: int myArray [] = new int [6]; myArray = new int [10]; 在这种情况下,第一个数组被有效地丢失,除非对它的其它引用保留在其它地方。 Java编程语言在System类中提供了一种特殊方法拷贝数组,该方法被称作arraycopy()。例如,araycopy可作如下使用: //原始数组 int myArray[] = { 1, 2, 3, 4, 5, 6 }; //新的数组,比原始数组大 int hold[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }; //把原始数组的值拷贝到新的数组 System.arraycopy(myArray, 0, hold, 0, myArray.length); 拷贝完成后,数组hold有如下内容:1,2,3,4,5,6,4,3,2,1。 注意—在处理对象数组时,System.arraycopy()拷贝的是引用,而不是对象。对象本身不改变。 六、命令行参数 当Java程序启动时,可以添加0或多个命令行参数(Command-line Arguments)。不管使用双引号与否都作为字符串自动保存到main函数的参数中。参数之间用空格分隔,使用双引号可以将带空格的几个串合为一个。 public class Test{ public static void main(String args[]){ System.out.println(args.length); for(int i=0; i System.out.println(args[i]); } } } 本段代码可以使用下面语句测试:java Test 这里 是 Java 私塾 运行结果: 4 这里 是 Java 私塾 七、数组的排序 在讨论数组排序之前,我们先来看看一些基本的排序方法: 1.冒泡排序 对几个无序的数字进行排序,比较常用的方法是冒泡排序法。冒泡法排序是一个比较简单的排序方法,在待排序的数列基本有序的情况下排序速度较快。 基本思路:对未排序的各元素从头到尾依次比较相邻的两个元素是否逆序(与欲排顺序相反),若逆序就交换这两元素,经过第一轮比较排序后便可把最大(或最小)的元素排好,然后再用同样的方法把剩下的元素逐个进行比较,就得到了你所要的顺序。 可以看出如果有N个元素,那么一共要进行N-1轮比较,第I轮要进行N-I次比较。(如:有5个元素,则要进行5-1轮比较。第3轮则要进行5-3次比较) 示例如下: public class Test { public static void main(String[] args) { //需要排序的数组,目前是按照升序排列的 int a[] = new int[5]; a[0] = 3; a[1] = 4; a[2] = 1; a[3] = 5; a[4] = 2; //冒泡排序 for(int i=0;i for(int j=i+1;j if(a[i] > a[j]){ int temp = a[j]; a[j] = a[i]; a[i] = temp; } } } //检测一下排序的结果 for(int i : a){ System.out.println("i="+i); } } } 运行结果: i=1 i=2 i=3 i=4 i=5 如果你想要按照降序排列,很简单,只需把:if(a[i] > a[j])改成:if(a[i] < a[j])就可以了。 另外给出一个冒泡排序算法的核心部分如下: int temp; for(int i=0; i { for(int j=0; j { if(a[j] > a[j+1]) { temp = a[j]; a[j] = a[j+1]; a[j+1] = temp; } } } 2.选择排序 基本思路:从所有元素中选择一个最小元素a[i]放在a[0](即让最小元素a[i]与a[0]交换),作为第一轮;第二轮是从a[1]开始到最后的各个元素中选择一个最小元素,放在a[1]中;……依次类推。n个数要进行(n-1)轮。比较的次数与冒泡法一样多,但是在每一轮中只进行一次交换,比冒泡法的交换次数少,相对于冒泡法效率高。 示例如下: public class Test { public static void main(String[] args) { //需要排序的数组,目前是按照升序排列的 int a[] = new int[5]; a[0] = 3; a[1] = 4; a[2] = 1; a[3] = 5; a[4] = 2; //选择法排序 int temp; for (int i = 0; i int lowIndex = i; //找出最小的一个的索引 for (int j=i+1;j if (a[j] < a[lowIndex]) { lowIndex = j; } } //交换 temp=a[i]; a[i]=a[lowIndex]; a[lowIndex]=temp; } //检测一下排序的结果 for(int i : a){ System.out.println("i="+i); } } } 运行结果: i=1 i=2 i=3 i=4 i=5 如果你想要按照降序排列,很简单,只需要把: if (a[j] < a[lowIndex])这句话修改成:if (a[j] > a[lowIndex])就可以了。 3.插入法排序 基本思路:每拿到一个元素,都要将这个元素与所有它之前的元素遍历比较一遍,让符合排序顺序的元素挨个移动到当前范围内它最应该出现的位置。 举个例子来说,就用前面的数组,我们要对一个有5个元素的数组进行升序排列,假设第一个元素的值被假定为已排好序了,那么我们就将第2个元素与数组中的部分进行比较,如果第2个元素的值较小,则将它插入到第1个元素的前面,现在就有两个元素排好序了,我们再将没有排序的元素与排好序的元素列表进行比较,同样,如果小于第一个元素,就将它插入到第一个元素前面,但是,如果大于第一个元素的话,我们就将它再与第2个元素的值进行比较,小于的话就排在第2个元素前面,大于的话,就排在第2个元素的后面。以此类推,直到最后一个元素排好序。 示例如下: public class Test { public static void main(String[] args) { // 需要排序的数组,目前是按照升序排列的 int a[] = new int[5]; a[0] = 3; a[1] = 4; a[2] = 1; a[3] = 5; a[4] = 2; // 插入法排序 int temp; for (int i = 1; i < a.length; i++) {// i=1开始,因为第一个元素认为是已经排好序了的 for (int j = i; (j > 0) && (a[j] < a[j - 1]); j--) { //交换 temp = a[j]; a[j] = a[j - 1]; a[j - 1] = temp; } } // 检测一下排序的结果 for (int i : a) { System.out.println("i=" + i); } } } 运行结果: i=1 i=2 i=3 i=4 i=5 如果你想要按照降序排列,很简单,只需要把: a[j] < a[j - 1]这句话修改成:a[j] > a[j - 1]就可以了。 4.希尔(Shell)法排序 从前面介绍的冒泡排序法,选择排序法,插入排序法可以发现,如果数据已经大致排好序的时候,其交换数据位置的动作将会减少。例如在插入排序法过程中,如果某一整数d[i]不是较小时,则其往前比较和交换的次数会更少。如何用简单的方式让某些数据有一定的大小次序呢?Donald Shell(Shell排序的创始人)提出了希尔法排序。 基本思路:先将数据按照固定的间隔分组,例如每隔4个分成一组,然后排序各分组的数据,形成以分组来看数据已经排序,从全部数据来看,较小值已经在前面,较大值已经在后面。将初步处理了的分组再用插入排序来排序,那么数据交换和移动的次数会减少。可以得到比插入排序法更高的效率。 示例如下: public class Test { public static void main(String[] args) { // 需要排序的数组,目前是按照升序排列的 int a[] = new int[5]; a[0] = 3; a[1] = 4; a[2] = 1; a[3] = 5; a[4] = 2; // shell法排序 int j = 0; int temp = 0; //分组 for (int increment = a.length / 2; increment > 0; increment /= 2) { //每个组内排序 for (int i = increment; i < a.length; i++) { temp = a[i]; for (j = i; j >= increment; j -= increment) { if (temp < a[j - increment]){ a[j] = a[j - increment]; }else{ break; } } a[j] = temp; } } // 检测一下排序的结果 for (int i2 : a) { System.out.println("i=" + i2); } } } 运行结果: i=1 i=2 i=3 i=4 i=5 如果你想要按照降序排列,很简单,只需要把:if (temp < a[j - increment])这句话修改成:if (temp > a[j - increment])就可以了。 5.数组排序 事实上,数组的排序不用那么麻烦,上面只是想让大家对一些基本的排序算法有所了解而已。在java.util.Arrays类中有一个静态方法sort,可以用这个类的sort方法来对数组进行排序。 示例如下: public class Test { public static void main(String[] args) { // 需要排序的数组,目前是按照升序排列的 int a[] = new int[5]; a[0] = 3; a[1] = 4; a[2] = 1; a[3] = 5; a[4] = 2; //数组排序 java.util.Arrays.sort(a); // 检测一下排序的结果 for (int i2 : a) { System.out.println("i=" + i2); } } } 注意:现在的sort方法都是升序的,要想实现降序的,还需要Comparator的知识,这个在后面会学到。 作业 1.下面的数组定义那些是正确的 A: int a[][] = new int[3,3]; B: int a[3][3] = new int[][]; C: int a[][] = new int[3][3]; D: int []a[] = new int[3][3]; E: int [][]a = new int[3][3]; 2.已知如下的命令执行 java MyTest a b c 请问哪个是正确的? A、args[0] = "MyTest a b c" B、args[0] = "MyTest" C、args[0] = "a" D、args[1]= 'b' 3.在命令行输入java X Y的结果是: public class X{ public void main(String []args){ System.out.println(“Hello ”+args[0]); } } A. Hello X Y B. Hello X C. Hello Y D. 不能编译 E. 运行时有异常 4:请在下面语句中找出一个正确的。 A. int arr1[2][3]; B. int[][] a2 = new int[2][]; C. int[][] arr2=new int [][4]; D. int arr3[][4]= new int [3][4]; 以下是编程题: 1.写一个方法,在方法内部定义一个一维的int数组,然后为这个数组赋上初始值,最后再循环取值并打印出来 2.用二重循环求出二维数组b所有元素的和: int[][] b={{11},{21,22},{31,32,33}} 3.编写一个方法实现将班级同学的名单存放在数组中,并利用随机数(Math.random())随机输出一位同学的姓名。 4.生成一百个随机数,放到数组中,然后排序输出。 Java私塾跟我学系列——JAVA篇 网址:http://www.javass.cn 电话:010-68434236
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/26660100/viewspace-715580/ ,如需转载,请注明出处,否则将追究法律责任。