定义
数组指的就是一组相关类型的变量集合,并且这些变量可以按照统一的方式进行操作。数组本身属于引用数据类型。其中每一个数据称作为一个数组元素,每个数组元素可以通过一个下标(索引)来访问它们。
数组声明
两种形式(方括号位置前后放变量都可以)
int arr[];
int[] arr; //常用
数组初始化
数组初始化也有两种形式(使用new和不使用new)
int arr[] = new int[]{1,3,5,7,9}
int[] arr = {2,4,6,8,10}
【实例】定义一个int型数组
package array;
//定义一个int型数组
public class Demo1 {
public static void main(String[] args) {
int[] arr; //声明一个数组
arr = new int[10]; //创建一个长度为10的数组
//给数组元素中赋值
arr[0]=1;//第一个元素
arr[1]=2;//第二个元素
arr[2]=3;
arr[3]=4;
arr[4]=5;
arr[5]=6;
arr[6]=7;
arr[7]=8;
System.out.println("第一个值为:"+arr[0]);
System.out.println("最后一个值为:"+arr[7]);
}
}
运行结果为:
第一个值为:1
最后一个值为:8
- 数组的访问通过索引完成,即:“数组名称[索引]”,但是需要注意的是,数组的索引从0开始,所以索引的范围就是0 ~ 数组长度-1,例如开辟了3个空间的数组,所以可以使用的索引是:0,1,2,如果此时访问的时候超过了数组的索引范围,会产生java.lang.ArrayIndexOutOfBoundsException 异常信息;
- 当我们数组采用动态初始化开辟空间后,数组里面的每一个元素都是该数组对应数据类型的默认值;(int类型默认值为0,String类型默认值为null)
- 数组本身是一个有序的集合操作,所以对于数组的内容操作往往会采用循环的模式完成,数组是一个有限的数据集合,所以应该使用 for 循环。
- 在 Java 中提供有一种动态取得数组长度的方式:数组名称.length;
public class array{
public static void main(String []args){
int[] arr = new arr[]{1,3,5,7,9}
int sum = 0;
for(int i = 0;i<arr.length;i++){
sum = sum + arr[i]
System.out.println(sum);
}
}
}
【int类型数组求和】
package array;
public class Demo2 {
public static void main(String[] args) {
int arr[] = new int[]{1,3,5,7,9};
int sum = 0;
for(int i = 0;i<arr.length;i++){
sum = sum + arr[i];
}
System.out.println("总和为:"+sum);
}
}
运行结果为:
总和为:25
数组的基本特点
- 其长度是确定的。数组一旦被创建,它的大小就是不可改变的。
- 其元素必须是相同类型,不允许出现混合类型。
- 数组中的元素可以是任何数据类型,包括基本类型和引用类型。
- 数组变量属于引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。
- 数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中的。
数组的常见异常
数组中最常见的问题:
-
NullPointerException 空指针异常
原因: 引用类型变量没有指向任何对象,而访问了对象的属性或者是调用了对象的方法。\ -
ArrayIndexOutOfBoundsException 索引值越界。
原因:访问了不存在的索引值。
一、数组角标越界异常:
注意:数组的角标从0开始。
public static void main(String[] args) {
int[] x = { 1, 2, 3 };
System.out.println(x[3]);
//java.lang.ArrayIndexOutOfBoundsException
}
二 、空指针异常:
public static void main(String[] args) {
int[] x = { 1, 2, 3 };
x = null;
System.out.println(x[1]);
// java.lang.NullPointerException
}
数组的使用
数组遍历
- 普通for循环
package array;
public class Demo3 {
public static void main(String[] args) {
int[] array = {1,3,5,7,9}; //创建一个数组
//遍历数组中的每一个元素
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
System.out.println("==========");
//计算数组中所有元素的和
int sum = 0;
for (int i = 0; i < array.length; i++) {
sum +=array[i];
}
System.out.println("sum="+sum);
System.out.println("==========");
//查找数组中的最大值
int Max = 0;
for (int i = 0; i < array.length; i++) {
if( array[i] > Max) {
Max = array[i];
}
}
System.out.println("Max="+Max);
}
}
运行结果:
2. 增强for循环
package array;
public class Demo4 {
public static void main(String[] args) {
int[] array = {2,4,6,8,10}; //创建array数组
prinArray(array); //调用printArray方法
reverse(array);
}
//打印数组元素
public static void prinArray(int[] array) { //定义prinArray方法
for (int i = 0; i < array.length; i++) {
System.out.print(array[i]+" ");
}
System.out.print("&&");
}
//反转数组元素
public static int[] reverse(int [] array) { //定义方法
int[] result = new int [array.length]; //定义反转数组
for (int i = 0,j = array.length-1; i < array.length ; i++,j--) {
result[j] = array[i];
System.out.print(" "+array[j]+" ");
}
return result;
}
}
运行结果:
二维数组
二维数组的定义有很多方式,接下来针对几种常见的方式进行详细地讲解,具体如下:
第一种方式:
int[ ][ ] arr = new int[3][4];
上面的代码相当于定义了一个3*4的二维数组,即二维数组的长度为3,二维数组中的每个元素又是一个长度为4的数组
第二种方式:
int[ ][ ] arr = new int[3][ ];
第二种方式和第一种类似,只是数组中每个元素的长度不确定,
第三种方式:
int[][] arr = {{1,2},{3,4,5,6},{7,8,9}};
上面的二维数组中定义了三个元素,这三个元素都是数组,分别为{1,2}、{3,4,5,6}、{7,8,9},
对二维数组中元素的访问也是通过角标的方式,如需访问二维数组中第一个元素数组的第二个元素,具体代码如下:
arr[0][1];
【实例】二维数组的元素访问
package array;
public class Demo5 {
public static void main(String[] args) {
//定义一个二维数组
int [][] array = {{1,2},{3,4},{5,6}};
System.out.println(array);
System.out.println("数组的长度为:"+array.length); //打印数组的长度。
//打印数组的三个元素
System.out.println(array[0]); //打印的不是数组元素的值而是数组的哈希值
System.out.println(array[1]);
System.out.println(array[2]);
//打印第一个一维数组的元素值
System.out.println("打印第一个一维数组元素");
System.out.println(array[0][0]);
System.out.println(array[0][1]);
}
}
运行结果:
【练习】公司销售总和
例如要统计一个公司三个销售小组中每个小组的总销售额以及整个公司的销售额。如下所示
第一小组销售额为{11, 12}万元
第二小组销售额为{21, 22, 23}万元
第三小组销售额为{31, 32, 33, 34}万元。
package array;
/*
要统计一个公司三个销售小组中每个小组的总销售额以及整个公司的销售额。如下所示
>
> 第一小组销售额为{11, 12}万元
>
> 第二小组销售额为{21, 22, 23}万元
>
> 第三小组销售额为{31, 32, 33, 34}万元。
*/
public class Demo6 {
public static void main(String[] args) {
int [][] arr = new int [3][]; //定义一个长度为3的数组
arr[0] = new int [] {11,12}; //给数组中元素赋值
arr[1] = new int [] {21,22,23};
arr[2] = new int [] {31,32,33,34};
int sum = 0; //定义公司销售总额初始值
int groupsum = 0; //定义小组总额初始值
for (int i = 0; i < arr.length; i++) { //遍历数组元素
for (int j = 0; j < arr[i].length; j++) { //遍历组内个人销售额
groupsum += arr[i][j]; //累加组内销售额
}
sum += groupsum; //累加小组销售额
System.out.println("第"+(i+1)+"小组销售额为:"+groupsum+"万元");
}
System.out.println("公司总销售额为:"+sum+"万元");
}
}
运行结果:
冒泡排序
**原理:**比较两个相邻的元素,将值大的元素交换到右边
思路:依次比较相邻的两个数,将比较小的数放在前面,比较大的数放在后面。
(1)第一次比较:首先比较第一和第二个数,将小数放在前面,将大数放在后面。
(2)比较第2和第3个数,将小数 放在前面,大数放在后面。
(3)如此继续,知道比较到最后的两个数,将小数放在前面,大数放在后面,重复步骤,直至全部排序完成
(4)在上面一趟比较完成后,最后一个数一定是数组中最大的一个数,所以在比较第二趟的时候,最后一个数是不参加比较的。
(5)在第二趟比较完成后,倒数第二个数也一定是数组中倒数第二大数,所以在第三趟的比较中,最后两个数是不参与比较的。
(6)依次类推,每一趟比较次数减少依次
算法分析:
(1)由此可见:N个数字要排序完成,总共进行N-1趟排序,每i趟的排序次数为(N-i)次,所以可以用双重循环语句,外层控制循环多少趟,内层控制每一趟的循环次数
(2)冒泡排序的优点:每进行一趟排序,就会少比较一次,因为每进行一趟排序都会找出一个较大值。如上例:第一趟比较之后,排在最后的一个数一定是最大的一个数,第二趟排序的时候,只需要比较除了最后一个数以外的其他的数,同样也能找出一个最大的数排在参与第二趟比较的数后面,第三趟比较的时候,只需要比较除了最后两个数以外的其他的数,以此类推……也就是说,没进行一趟比较,每一趟少比较一次,一定程度上减少了算法的量。
(3)时间复杂度
1.如果我们的数据正序,只需要走一趟即可完成排序。所需的比较次数C和记录移动次数M均达到最小值,即:Cmin=n-1;Mmin=0;所以,冒泡排序最好的时间复杂度为O(n)。
2.如果很不幸我们的数据是反序的,则需要进行n-1趟排序。每趟排序要进行n-i次比较(1≤i≤n-1),且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较和移动次数均达到最大值:
综上所述:冒泡排序总的平均时间复杂度为:O(n2) ,时间复杂度和数据状况无关。
【代码实例1】
package array;
//冒泡排序
public class Demo7 {
public static void main(String[] args) {
int [] array = {1,5,8,5,14,66,21,5521,520};
Sort(array); //调用方法
}
public static void Sort(int[] array) {
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array.length-i-1; j++) {
if (array[j] > array[j+1]) {
int temp = array[j]; //定义第三变量,便于元素比较交换
array[j] = array[j+1];
array[j+1] = temp;
}
}
}
System.out.println("从小到大:");
for (int i = 0; i < array.length; i++) {
if (i == array.length-1) {
System.out.println(array[i]);
}else {
System.out.print(array[i]+" ,");
}
}
}
}
运行结果:
【代码实例2】
package array;
import java.util.Arrays; //工具类
/*
冒泡排序
1、比较数组中两个相邻的元素,如果第一个数比第二个数大,则交换它们的位置
2、每一次比较,都会产生一个最大的数或者最小的数。
3、下一轮则可以少一次排序。
4、依次循环,直到结束。
*/
public class Demo8 {
public static void main(String[] args) {
int [] a = {5,2,88,12,19,520,30};
int[] sort = sort(a); //调用完我们自己写的排序方法以后,返回一个排序后的数组
System.out.println(Arrays.toString(sort));
}
public static int[] sort(int[] array) {
int temp = 0; //定义一个临时变量,便于元素比较交换位置
for (int i = 0; i < array.length-1; i++) {
for (int j = 0; j < array.length-i-1; j++) {
if (array[j+1] > array[j]) {
temp = array[j]; //元素比较交换
array[j] = array[j+1];
array[j+1] = temp;
}
}
}
return array;
}
}
运行结果:
稀疏数组
当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组,稀疏数组的处理方法是:
记录数组一共有几行几列,有多少个不同的值, 把具有不同值的元素的行列及值记录在一个小规模的数组中,从而缩小程序的规模
应用实例
-
使用稀疏数组,来保留类似前面的二维数组(棋盘、地图等等)
-
把稀疏数组存盘,可以重新恢复原来的二维数组数
-
思路分析
-
代码实现:
package array;
//稀疏数组
public class Demo9 {
public static void main(String[] args) {
//创建一个二维数组11*11
//0表示没有棋子,1表示黑棋,2表示白棋。
int [][] arr1 = new int[11][11];
arr1[1][2] = 1;
arr1[2][3] = 2;
//打印原始的二维数组。
System.out.println("原始的二维数组:");
for (int i = 0; i < arr1.length; i++) {
for (int j = 0; j < arr1[i].length; j++) {
System.out.print(arr1[i][j]+" ");
}
System.out.println();
}
//将二维数组转换为稀疏数组
//先遍历二维数组得到非零元素的个数
int sum = 0;
for (int i = 0; i < 11; i++) {
for (int j = 0; j < 11; j++) {
if (arr1[i][j] != 0) {
sum++;
}
}
}
//创建对应的稀疏数组
int [][] arr2 = new int [sum+1][3];
//给稀疏数组赋值
arr2[0][0] = 11;
arr2[0][1] = 11;
arr2[0][2] = sum;
//遍历二维数组将非零的元素值存放到稀疏数组中
int count = 0;
for (int i = 0; i < arr1.length; i++) {
for (int j = 0; j < arr1[i].length; j++) {
if (arr1[i][j] != 0) {
count++;
arr2[count][0] = i;
arr2[count][1] = j;
arr2[count][2] = arr1[i][j];
}
}
}
//打印稀疏数组
System.out.println();
System.out.println("稀疏数组");
System.out.println("稀疏数组的有效值个数为 :"+sum);
for (int i = 0; i < arr2.length; i++) {
System.out.println(arr2[i][0]+" "+arr2[i][1]+" "+arr2[i][2]);
}
//将稀疏数组还原成二维数组
//先读取稀疏数组的第一行,根据第一行创建二维数组
int [] [] arr3 = new int [arr2[0][0]][arr2[0][1]];
//读取稀疏数组中有效值元素并赋值给二维数组
//注意: 数组是从第二行开始
for (int i = 1; i < arr2.length; i++) {
arr3[arr2[i][0]][arr2[i][1]] = arr2[i][2];
}
System.out.println();
System.out.println("恢复后的二维数组:");
for (int[] row : arr3) {
for (int data : row) {
System.out.print(data+" ");
}
System.out.println();
}
}
}
运行结果: