Java基础——数组
数组是一个语言中的基本要素,它能够用来保存和管理多个变量。例如,如果要统计三个学生的成绩,可以手动的定义三个变量 a、b、c,如果要输出这三个变量的值,也可以写三个输出语句。但是,如果要管理一个年级所有学生的成绩,此时,可能有上百个学生。如果为每个学生都手动定义一个变量的话,则程序中会有上百个变量。并且,如果要 输出所有学生的成绩,就会有上百个输出语句。很显然,这样的代码是非常复杂和繁琐的。
因此,我们就需要有一个办法,能够比较方便的管理多个数据。在这种情况下,我们就应该用到数组。
一、数组的基本操作
数组:一次性定义多个同类型的变量。
数组空间在内存中必定是连续的。
1,创建数组
int []a 或int a[] 表示定义一个int类型的一维数组变量a
a=new int[3]; 表示分配了一个长度为3个int的内存空间
int[]a=new int[3]; 也可以两部写在一块,表示定义一个int类型的一维数组同时分配长度为3个int的内存空间
2,下标
定义一个数组,就是一次性定义多个同类型的变量。为数组分配完空间之后,就可以使用数组了。使用数组的时候,应当用下标来表示数组元素。例如,上面分配了长度为3个int 类型的变量,这3个int 变量分别可以用:a[0]、a[1]、a[2]来表示。
即如果分配了一个长度为 n 的数组,则数组的下标范围为 0~n-1。
a[0] = 10; //对数组元素进行赋值
a[1] = 20;
a[2] = 30;
3,遍历数组
遍历数组:按照一定顺序,把每个元素都访问一遍,不会遗漏,不会重复
示例代码:
package p5; public class TestArray{ public static void main(String [] args){ int[]a;//数组的定义 int []a; int a []; a=new int[3];//初始化变量a,为数组分配空间,定义数组的长度 a[0]=1; a[1]=2; a[2]=3;//数组的赋值 for(int i=0;i<3;i++){//遍历数组 System.out.println(a[i]); } } }
运行结果:
4,数组的初始化
数组元素在没有赋值的情况下可以使用,数组元素有特定的默认值
byte、short、int、long 这四种整数类型,默认值为 0
float 和 double 这两种小数类型,默认值为 0.0
boolean 默认值为 false
char 默认值也为 0
注意,char 类型的 0 不是指的字符‘0’,而是指的编码为 0。
对于对象类型的数组来说,默认值为 null。
显示初始化
第一种形式如下:
int[] a = {10, 20, 30};
特点是,只能在定义数组变量的同时使用。
第二种语法形式如下:
int[] a = new int[]{10, 20, 30};
注意,这种语法下,new 关键字后面的方括号中没有数字,也就是说,显式初始化时不能规定数组长度,数组长度由后面的元素个数决定。
package p5; public class TestArray{ public static void main(String [] args){ int[]a;//数组的定义 int []a; int a []; a=new int[3];//初始化变量a,为数组分配空间,定义数组的长度 a[0]=1; a[1]=2; a[2]=3;//数组的赋值 /* int[]a={1,2,3};//数组的显示初始化,数组长度有括号内元素个数决定 //int []a=new int [](1,2,3); //int []a=new int [3](1,2,3); error!!! */ for(int i=0;i<3;i++){//遍历数组 System.out.println(a[i]); } } }
二、数组在内存中的表示
Java 数组在内存中的表示情况。看下面两行代码
int[] a; a = new int[3];
我们结合代码,分析一下数组在内存中的表示。
第一行,定义了一个数组变量 a,此时没有分配连续的内存空间。
第二行,首先执行了 new int[3],这句代码分配了一个段连续的内存空间,总共能够放 入 3 个 int,因此是 12 个字节。这 12 个字节每个字节都有自己的一个内存地址,其中,12 个字节中的第一个字节,它的地址被称之为这块内存的“首地址”。假设首地址为 1a2b。第三步,执行完了 new int[3]之后,进行了赋值。究竟是把什么赋值给了变量 a 呢?注 意,赋值赋的是内存的首地址。也就是说,数组变量保存的是数组中的首地址 1a2b。如下图所示
三、二维数组
1,二维数组的基本操作
二维数组以及多维数组:数组的数组。
比如说,我们日常生活中的抽屉,我们可以认为抽屉就是用来存放多个物品的,因此抽屉就是一个物品的数组。而一个柜子中,可以存放多个抽屉,因此我们可以理解为,柜子就是抽屉组成的数组。因此,柜子就可以理解为是“数组的数组”,也就是:柜子的元素是抽屉,而抽屉本身又是一个数组。
Ⅰ,创建二维数组
int[][] a; 或者 int[] a[]; 或者 int a[][];
定义二维数组变量的时候,同样没有分配数组空间。
a = new int[3][4];
为二维数组分配内存空间,分配一个三行四列的二维数组
我们可以这 么来看:我们分配的这个二维数组就相当于一个柜子,这个柜子有三层,每层放一个抽屉。这个抽屉里面分成了四个格子,每个格子又能放一个元素。由于二维数组是“数组的 数组”,因此,二维数组的“行”,指的是这个二维数组中,包含几个元素。由于二维数组 的元素是一维数组,因此,“行”也就是二维数组中包含几个一维数组。而列,则指的是, 二维数组中的每一个一维数组,各自都包含几个元素。
a[0][2]
表示第 0 行第 2 列的元素
int [][]a={{1,2,3}{5,6,7}{8,9,10}{11,12,13}};
二维数组的显示初始化
Ⅱ,遍历二维数组
遍历二维数组时,要获得行和列两个数值。
首先,二 维数组同样有 a.length 这样的变量,而使用 a.length 获得的长度,是二维数组元素的个数, 也就是行的数目,也可以理解成:柜子里抽屉的个数。而列的数目,就相当于是每一个一 1a2b a … … 1a2b 7 维数组的长度,也可以理解为,是每一个抽屉的大小。对于第 i 个抽屉,我们可以使用 a[i].length 来获得它的长度。
示例代码:
package p5; public class TestArray2{ public static void main(String [] args){
//int [][]a=new int[4][3];//二维数组变量的定义,并为二维数组分配内存空间,
//分配一个三行四列的二维数组 // int [][]a=new int [][3];//error!!! int [][]a={{1,2,3},{5,6,7},{8,9,10},{11,12,13}};//二维数组的显示初始化 for(int i=0;i<a.length;i++){//遍历二维数组 for(int j=0;j<a[i].length;j++){ System.out.print(a[i][j]+" "); } System.out.println(); } } }
运行结果:
2,二维数组的内存表示
对于 a 数组来说,它还是一个一维数组,这个一维数组的长度为 3,也就 是说,a 数组有三个元素。而 a[0],a[1],a[2]又各自记录了一个一维数组的地址。因此我们把 a 数组称为“一维数组的一维数组”,也就是二维数组。
3,不规则数组
除了普通的二维数组之外,Java 还支持不规则数组。举例来说,如果一个柜子有三个 抽屉,这个三个抽屉中并不一定每个抽屉都具有一样的大小,完全有可能第三个抽屉更 大,元素更多,而第一个抽屉相对就比较小。
int[][] a; //定义数组变量
a = new int[3][]; //先确定第一个维度,表明柜子里有三个抽屉 a = new int[][3]; //error!
a[0] = new int[3]; //上层的抽屉有三个元素
a[1] = new int[4]; //下一层有四个元素
a[2] = new int[5]; //最底层有五个元素
四,数组的常见算法
1,数组的扩容
首先,数组空间一旦分配完成之后,长度就不能改变了。因此,我们不能够直接在原 有数组的空间后面增加新的内存空间。我们可以采用以下方式,来增加数组的长度:
①、分配一个新的数组,新数组的长度比原有数组要大(比如长度是原有数组的两倍)
②、把原有数组中的数据,复制到新数组中。
package p5; import java.util.Arrays; public class TestArrayExpand{ public static void main(String []args){ int []a={1,2,3,4};//定义数组a,并显示初始化a int []b=new int[8];//定义数组b,并为b分配内存空间, a=expand(a); } public static int[] expand(int[]a){//扩充方法1 int []b=new int[a.length*2]; for(int i=0;i<a.length;i++){ b[i]=a[i]; } return b; } public static int []expand1(int []a){//扩充方法2 int []b=new int [a.length*2]; System.arraycopy(a,0,b,0,a.length); return b; } public static int []expand2(int []a){//扩充方法3 return Arrays.copyOf(a,a.length*2); } }
2,冒泡排序
在排序的过程中,相邻元素不停进行比 较和交换。在交换的过程中,大的元素沉向数组的末尾,小的元素走向数组的开头;这就好像在水里面:重的东西往下沉,而轻的东西往上浮起来。正因为这种排序方式很像水里 的气泡往上浮的过程,因此,这种排序方式被称为冒泡排序。
接下来,我们来写冒泡排序的代码。如果有五个元素,则需要进行 4 次循环,也就是 说,如果数组的长度是 a.length 的话,则需要进行 a.length-1 次循环。因此,外层循环如下:
for(int i = 0; i<a.length-1; i++){ … }
内层循环稍有点复杂。我们让内层循环的循环变量为 j,则每次进行比较的时候,比较 的都是 a[j]和 a[j+1]这两个元素。那么 j的循环条件怎么写呢?
第 1 次循环,i 的值为 0,因为要排到最后一个,因此 j+1 最大值为 a.length,j 的最大值为 a.length-1;
第 2 次循环,i的值为 1,j+1 的最大值为 a.length-1,j的最大值为 a.length-2;
第 3 次循环,i的值为 2,j+1 的最大值为 a.length-2,j的最大值为 a.length-3;
由上面,我们可知,每次循环 j+1 的最大值,都是 a.length-i;而 j 的最大值,就是 a.length-i-1。 因此,内层循环条件如下:
for(int i = 0; i<a.length-1; i++){ for(int j = 0; j<a.length–i-1; j++){ 比较 a[j]和 a[j+1], 如果 a[j]比 a[j+1]大,则交换两个元素的值 13 } }
进一步细化,代码为
for(int i = 0; i<a.length-1; i++){ for(int j = 0; j<a.length–i-1; j++){ if(a[j] > a[j+1]){ 则交换 a[j]和 a[j+1]的值 } } }
如何交换两个变量的值呢?假设有两个变量 a = 5;b=4;要交换两个 a 和 b 的值,应该怎么做呢?
如果直接执行 a = b 的话,则 a 的值 5 就会被 b 的值覆盖。这样,a 有了 b 的值,但是 b 却无法获得 a 变量原来的值了。因此,为了交换两个变量的值,需要第三个变量参与。
首先,定义一个新变量 t; 然后,把 a 的值赋值给 t:t = a;
接下来,把 b 的值赋值给 a: a=b。这样会覆盖 a 原有的值,但是没关系,a 原有的值 已经被保存在 t 变量中了。
再接下来,把在 t 变量中保存的原有的 a 变量的值,赋值给 b。
示例代码:
package p5; public class TestArraySort{ public static void main(String[]args){ int []data={5,4,2,1,3};//定义一个一维数组,并显示初始化数组 int n=data.length;//定义变量n为数组长度,便于后面使用数组长度 for(int i=1;i<n;i++){//冒泡排序必定是n-1次,i表示第几次冒泡排序 for(int j=0;j<(n-i);j++){//归纳总结,从0开始data[j]与data[j+1]比较,比较n-i次 if(data[j]>data[j+1]){ int t=data[j]; data[j]=data[j+1]; data[j+1]=t;//data[j]与data[j+1]交换位置 } } } for(int i=0;i<data.length;i++){ System.out.print(data[i]+" ");//遍历输出data[i] } System.out.println();//换行 } }
运行结果:
3,选择排序
选择排序是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。选择排序是不稳定的排序方法(比如序列[5, 5, 3]第一次就将第一个[5]与[3]交换,导致第一个5挪动到第二个5后面)
package p5; public class TestArraySort{ public static void main(String[]args){ int []data={5,4,2,1,3};//定义一个一维数组,并显示初始化数组 int n=data.length;//定义变量n为数组长度,便于后面使用数组长度 for(int i=0;i<(n-1);i++){//选择排序 for(int j=i+1;j<n;j++){ if(data[i]>data[j]){ int t=data[i]; data[i]=data[j]; data[j]=t; } } } for(int i=0;i<data.length;i++){ System.out.print(data[i]+" ");//遍历输出data[i] } System.out.println();//换行 } }