4. 数组
-
数组(Array),是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理
-
数组属于引用型变量,数组元素既可以是引用型变量,也可以是基本类型数据变量
-
创建数组对象会在内存中开辟一整块连续的空间,而数组名中引用的是这块连续地址的首地址
-
数组的长度一旦确定(数组被初始化)就不能修改
-
声明方式:
int a[]; int[] a; double b[]; String[] c; int a[5]; //Java声明数组时,不能指定其长度
-
初始化:
-
动态初始化:数组声明且为数组分配空间与赋值操作分开进行
int[] arr = new int[2]; arr[0]=1; arr[1]=2;
-
静态初始化:在定义数组的同时就为数组元素分配空间并赋值
int arr[] = new int[]{1,2}; int arr[] = {1,2}//也是正确的:类型推断
-
-
数组是引用型,它的元素相当于类的成员变量,因此数组一旦被初始化,其中的每个元素也被按照成员变量同样的方式被隐式初始化
- 基本数据类型默认值为0
- 引用数据类型默认值为null
- boolean类型默认值为false
int a[] = new int[2]; System.out.println(a[2]);//0 0
-
数组的使用:
-
获取数组的长度
array.length
-
遍历数组
for(int i=0;i<array.length;++i){ System.out.println(array[i]); }
-
-
数组的内存解析:
- 内存的简化结构
-
代码解析
int arr1[] = new int[4]; arr1[0]=10; arr1[2]=20; String[] arr2 = new String[3]; arr2[1]="数组"; arr2 = new String[5];
- 放在方法里的变量叫局部变量,存放在栈里
- new 出来的东西放在堆中,如数组new 出来的一片连续的空间
- 连续空间的首地址值(用16进制表示)赋给栈中的局部变量
-
思考一(数组的复制):
int[] arr1,arr2; arr1= new int[] {2,3,5,7,13}; arr2=arr1; for(int i=0;i<arr2.length;++i){ if(i%2==0){ arr2[i]=i; } } //此时arr1的元素是什么情况? //打印arr1:0,3,2,7,4
只是将堆中的连续空间的首地址赋值给了arr2,此时栈中的arr1、arr2指向堆中同一块空间
-
思考二:
int[] arr1,arr2; arr1= new int[] {2,3,5,7,13}; arr2= new int[arr1.length];//只有new才会给arr2在堆中开辟空间 for(int i=0;i<arr1.length;++i){ arr2[i]=arr[i]; }
-
多维数组的使用:
-
二维数组
-
可以看成是一维数组array1又作为另一个一维数组array2的元素而存在;从底层的运行机制来看,其实没有多维数组
-
声明格式:
-
格式1:
int[][] arr = new int[3][2];
-
格式2:
int[][] arr = new int[3][];
每一个一维数组都是默认的null,可以分别对这三个一维数组分别进行初始化:
arr[0] = new int[3]; arr[1] = new int[1]; arr[2] = new int[2];//每个数组长度可以不同
-
格式3:
int[][] arr = new arr[][]{{1,2,3},{4},{5,6}}; int[] arr[] = new arr[][]{{1,2,3},{4},{5,6}};//正确 int[] arr[] = {{1,2,3},{4},{5,6}};//正确
-
-
二维数组的长度
int[][] arr = new arr[][]{{1,2,3},{4},{5,6}}; System.out.println(arr.length);//3 System.out.println(arr[1].length);//1
-
二维数组的遍历
for(i=0;i<arr.length;++i){ for(j=0;j<arr[i].length;++j){ System.out.print(arr[i][j]+" "); } }
-
二维数组的初始化
-
外层元素:arr[0]、arr[1]
-
内层元素:arr[0] [0]
int arr[][] = new int[4][3]; System.out.println(arr[1]); //[I@15db9742:第二个一维数组的内存首地址 System.out.println(arr[1][2]); //0:内层元素默认值为0 System.out.println(arr); //[[I@6b6098b3:二维数组的内存首地址 //[[:二维数组、I:int类型 float arr[][] = new float[4][3]; System.out.println(arr[1]);//[F@15db9742 System.out.println(arr[1][1]);//0.0 String arr[][] = new String[4][3]; System.out.println(arr[1]);//[Ljava.lang.String;@15db97 System.out.println(arr[1][1]);//null
-
使用
int[][] arr = new int[3][]; System.out.println(arr[1]);//null(引用类型默认值为null)
内存解析:
-
-
-
-
数组中常见的算法:
-
数组元素的赋值:
-
打印杨辉三角
public static void main(String[] args) { int[][] arr = new int[10][]; for(int i=0;i<arr.length;i++){ //初始化 arr[i]= new int [i+1]; //构造 arr[i][0]=1; arr[i][i]=1; if(i>1){ for(int j=1;j<arr[i].length-1;j++){ arr[i][j]=arr[i-1][j-1]+arr[i-1][j]; } } } //遍历打印 for(int i=0;i<arr.length;i++){ for (int j=0;j<i+1;j++){ System.out.print(arr[i][j]+" "); } System.out.println(); } }
-
回形数
-
赋值随机数
//Math.random():[0.0,1)(左闭右开) //表示[10,99]之间的随机数 (int)(math.random()*(99-10+1))+10; //公式[a,b] (int)(math.random()*(b-a+1))+a;
-
-
求数值型数组元素的max、min、平均值、总和:
public static void main(String[] args) { int[] arr = new int[10]; for (int i = 0; i < arr.length; ++i) { arr[i] = (int) (Math.random() * (99 - 10 + 1) + 10); } int maxValue = 0; for (int i = 0; i < arr.length; ++i) { if(arr[i]>maxValue){ maxValue=arr[i]; } } System.out.println("最大值为:"+maxValue); }
-
数组的复制、反转、查找:
-
数组的复制:
int[] arr1,arr2; arr1= new int[] {2,3,5,7,13}; arr2=arr1; for(int i=0;i<arr2.length;++i){ if(i%2==0){ arr2[i]=i; } } //此时arr1的元素是什么情况? //打印arr1:0,3,2,7,4
只是将堆中的连续空间的首地址赋值给了arr2,此时栈中的arr1、arr2指向堆中同一块空间
int[] arr1,arr2; arr1= new int[] {2,3,5,7,13}; arr2= new int[arr1.length];//只有new才会给arr2在堆中开辟空间 for(int i=0;i<arr1.length;++i){ arr2[i]=arr[i]; }
-
数组的反转:
int temp=0; for(int i=0;i<arr.length;++i){ temp=arr[i]; arr[i]=arr[arr.length-i-1]; arr[arr.length-i-1]=temp; }
-
查找:
-
线性查找:
String str = "abc"; boolean isFlag=true; for(int i=0;i<arr.length;++i){ if(str.equals(arr[i])){ System.out.println("找到了,位置为:"+i); isFlag=false; break; } } if(isFlag=true){ System.out.println("没有找到"); }
-
二分法查找:顺序存储且有序
public static void main(String[] args) { int[] arr = new int[]{-98,-34,2,34,54,66,79,105,210,333}; int key = -34; int low = 0; int high = arr.length-1; boolean isFlag=true; while(low <= high){ int mid = (low +high)/2; if(key == arr[mid]){ System.out.println("找到了:位置为"+ mid); isFlag=false; break; } else if(key<arr[mid]){ high = mid-1; }else{ low = mid+1; } } if(isFlag=true){ System.out.println("没有找到"); } }
-
-
-
数组元素的排序算法:
-
分类:
- 内部排序:整个排序过程不需要借助于外部存储器(如磁盘等),所有排序操作都在内存中完成
- 外部排序:参与排序的数据非常多,数据量非常大,计算机无法把整个排序过程放在内存中完成,必须借助于外部存储器(如磁盘)。外部排序最常见的是多路归并排序。可以认为外部排序是由多次内部排序组成
-
冒泡排序:
public static void main(String[] args) { int[] arr = new int[]{43,12,56,3,55,67,31}; for(int i=0;i<arr.length-1;++i){ //控制第几轮 for(int j=0;j<arr.length-1-i;++j){ //控制每轮中的起泡 if(arr[j]>arr[j+1]){ int temp = arr[j]; arr[j]=arr[j+1]; arr[j+1]=temp; } } } for(int i=0;i<arr.length;++i){ System.out.print(arr[i]+" "); } }
-
-
-
Arrays工具类使用:
java.util.Arrays类即为操作数组的工具类,包含了用来操作数组的各种方法
public static void main(String[] args) { int[] arr1 = new int[]{1,2,3}; int[] arr2 = new int[]{1,2,3}; int[] arr3 = new int[]{1,3,6,7}; //比较两个数组的内容 boolean isEquals = Arrays.equals(arr1,arr2); //以字符串类型输出数组的内容 String str = Arrays.toString(arr1); //将数组中所有元素替换成指定值 Arrays.fill(arr1,4); //对数组进行排序,底层使用的快排 Arrays.sort(arr3); //对数组进行二分查找 int index = Arrays.binarySearch(arr3,6); }
-
数组使用过程中的 常见异常
-
数组脚标越界异常(ArrayIndexOutOfBoundsException)
int[] arr = new int[2]; System.out.println(arr[2]);//脚标越界 System.out.println(arr[-1]);
-
空指针异常(NullPointerException)
int[] arr = null; System.out.println(arr[0]); //arr引用没有指向实体,却在操作实体中的元素时。
-