一、数组的定义与使用
1.数组的基本概念
1.1 为什么要使用数组
数组是最简单的一种数据结构 组织一组相同类型数据的集合
数据结构本身是来描述和组织数据的 数据加结构
1.2.1 数组的创建
代码实现
new int 可省略;
char[] chars={'a','b','c'}; //定义一个整形类型数组 int[] array={1,2,3,4,5}; //创建数组对象 int[] array2=new int[]{1,2,3,4,5}; int[] array3=new int[5];//数组中的值默认初始化为0
1.2.2 数组的初始化
数组的初始化分为动态初始化和静态初始化
1.动态初始化:在创建数组时,直接指定数组中元素的个数
int[] arr = new int[10];
2.静态初始化:在创建数组时,不需要直接指定数据元素个数,而直接将具体的数据内容进行指定
语法格式:T[] 数组名 = {data1,data2,...,datan}
注意事项
数组也可以按照C语言格式创建
静态和动态初始化也可以分为两步,但是省略格式不可以
int arr[]={data1,data2,...datan}
赋值的时候必须加上new
如果没有对数组进行初始化,数组中元素有其默认值
boolean类型初始值是false
数组的初始值为0
string等引用类型的初始值为null
1.3 数组的使用
1.3.1 数组中元素的访问
数组在内存中是一块连续的空间,空间的编号是从0开始的,依次递增,该编号称为数组的下标,数组可以通过下标访问其任意位置的元素
public class day_10 { //通过下标访问数组元素 int[] array={1,2,3,4,5}; System.out.println(array[5]);//越界 数组下标超出范围,数组越界异常 } }
越界异常结果
Java当中的内存划分是什么样子的?JVM当中的内存划分
array叫做引用变量->引用 引用指向对象的
当数组中元素为空时,要赋值变量为null
引用变量时会发生空指针异常
求数组长度
数组名.length; 求数组长度
//求数组长度 System.out.println(array.length);
数组名存的是存储数据对象的地址
所以数组存放的是数据对象的地址
引用 指向 对象
array2这个引用不指向任何对象
int[] array2=null;
局部变量在使用时,一定要先进行初始化
注意事项
1.数组是一段连续的内存空间,因此支持随机访问,即通过下标访问快速访问数组中任意位置的元素
2.下标从0开始,介于(0,n)之间不包含n,n为元素个数,不能越界,否则会报出下标越界异常
1.3.2 遍历数组
方式1
数组名.length
方式2
int x:数组名
方式3 1.3.3 数组是引用类型
1.3. 3.1 初识JVM的内存分布
内存是一段连续的存储空间,主要用来存储程序运行时数据的,比如:
意义:内存很大,但是,我们如果堆内存进行一个划分之后,我们可以更好地管理内存这块区间
Java的存储细节——五个区域
1.3.4 基本类型变量与引用类型变量的区别
基本变量存储在栈上,引用变量存储在堆上
引用变量array1=array2的意义:
1.3.5 认识null
int[] array = null; 代表array这个引用不指向任何对象
注意:Java中没有约定null和0号地址的内存有任何关联
引用参数变量
public static void print(int[] array){ for (int i = 0; i < array.length; i++) { System.out.print(array[i]+" "); } } public static void main(String[] args) { int[] array={1,2,3,4};//局部变量 引用变量 print(array); }
public static void print(int[] array){ for (int i = 0; i < array.length; i++) { System.out.print(array[i]+" "); } } public static void func1(int[] array){ array=new int[]{45,63,27,9,81}; } public static void func2(int[] array){ array[0]=99;//形参当中改变了实参的值 } public static void func3(int[] array){ int tmp=array[0]; array[0]=array[1]; array[1]=tmp; } public static void main(String[] args) { int[] array={1,2,3,4};//局部变量 引用变量 print(array); System.out.println(); func1(array); System.out.println(array); func2(array); System.out.println(array); func3(array); System.out.println(array); //[I@2f7a2457 //[I@2f7a2457 //不是传了引用就能改变值 //Java当中即使传递引用地址也不一定能改变实参的值 }
1.引用变量当中存的是地址
2.引用指向变量、地址也是一种值
Java当中只有传值调用一种
传值调用改变不了形参的值
public static void func4(int a){ a=20; } int x=10; func4(x); System.out.println(x);
2.作为函数的参数
1.参数传基本数据类型
因为java当中只支持传值调用,所以在方法内部修改形参不能影响实参的值
2.参数传数组类型(引用数据类型)
同样是传地址,引用数据类型传值可以修改其中存放的数据内容
public static void func5(int a[] ){ a[0]=99; } func5(array); System.out.println(array[0]);
总结
所谓的“引用“本质上只是存了一个地址,java将数组设定为引用类型,这样的话后续进行数组参数传参,其实只是将数组的地址传入搭配函数形参中,这样可以避免对整个数组的拷贝(数组如果较长,拷贝的开销就很大)
3.数组作为函数的返回值
public static int[] func6(){ int[] array={1,2,3,4}; return array; } int[] y=func6(); System.out.println(y[1]); System.out.println(func6());//还会打印地址
4.数组练习题
1 获取斐波那契数列的前n项
代码实现
public static int[] fib(int n){ if(n<=0){ return null; } int[] array=new int[n]; array[0]=array[1]=1; for (int i = 2; i < n; i++) { array[i]=array[i-1]+array[i-2]; } return array; } public static void main(String[] args) { //斐波那契数列前n项 int[] arr=fib(10); for (int i = 0; i < arr.length; i++) { System.out.print(arr[i]+" "); } }
运行结果
2.将数组转变为字符串进行返回
把一个整形数组转化为字符串
@param array 数组参数
@return 将数组转变为字符串返回
代码实现
public static String myToString(int[] array){ if(array==null){ return "null"; } String ret="["; for (int i = 0; i < array.length; i++) { ret+=array[i]; if(i!= array.length-1){ ret+=","; } } ret+="]"; return ret; } public static void main(String[] args) { int[] arr1={1,2,3,4,5,6}; String newArr=myToString(arr1); System.out.println(newArr); }
运行结果
3.数组拷贝
赋值不是拷贝
方法一 通过Arrays进行拷贝 Arrays.copyOf字符串拷贝函数
代码实现
public static void main(String[] args) { int[] arr2={1,2,3,4}; //根据工具类直接拷贝 拷贝数组,长度为arr2.length int[] copy=Arrays.copyOf(arr2,arr2.length); //根据工具类直接拷贝 拷贝数组,长度为arr2.length*2 //让arr指向新的空间 二倍进行扩容 System.out.println(Arrays.toString(copy)); copy=Arrays.copyOf(arr2,arr2.length*2); System.out.println(Arrays.toString(copy)); }
运行结果
方法二 通过数组名.clone进行拷贝
代码实现
int[] copy3=arr3.clone(); System.out.println(Arrays.toString(copy3));
运行结果
拷贝限制长度的数组
通过Arrays.copyOfRange(数组名,开始位置,结束位置)
代码实现
public static void main(String[] args) { int[] arr2={1,2,3,4}; //拷贝数组部分长度 int[] arr3={1,2,3,4,5}; int[] copy2=Arrays.copyOfRange(arr3,1,3); System.out.println(Arrays.toString(copy2)); }
运行结果
4.求数组中元素的平均值,给定一个整形数组,求平均值
要点:记得转换为double类型 否则无法输出 方法的返回值也设置为double类型
代码实现
public static double AVG(int[] arr){ int sum=0; for(int x:arr){ sum+=x; } return (double)sum/(double)arr.length; } public static void main(String[] args) { int[] arr4={1,2,3,4,5,6}; double avg=AVG(arr4); System.out.println(avg); }
运行结果
5.查找数组中指定元素(顺序查找)
代码实现
public static int Find(int[] arr,int data){ for (int i = 0; i < arr.length; i++) { if(arr[i]==data){ return i; } } return -1; } public static void main(String[] args) { int arr[]={1,2,3,4,5,6,7,8,9}; int i=Find(arr,9); System.out.println(i); }
运行结果
6.二分查找
建立在当前数组有序的情况下
思路
一直找到最中间的元素,查询元素与最中间的元素比大小,如果小则让左区间加一,如果大则让右区间-1,重复查询左区间和右区间和的二分之一,所以只适用于当前数组元素有序的情况下,如果查询不到则返回负的当前数组长度+1的值
代码实现
public static int ErFind(int[] arr,int key){ int i=0; int j= arr.length-1; while (i<=j){ int mid=(i+j)/2; if(arr[mid]<key){ i=mid+1; } else if (arr[mid]==key) { return mid; }else { j=mid-1; } } return -1 ; } public static void main(String[] args) { int[] array={1,2,31,14,5,8}; //数组排序 Arrays.sort(array); System.out.println(Arrays.toString(array)); System.out.println(Arrays.binarySearch(array,51)); System.out.println(Arrays.binarySearch(array,31)); }
运行结果
7.数组元素逆序
思路
while循环进行两元素的交换,传值调用进行交换
代码实现
//习题7 数组元素逆序 public static void reverse(int[] array){ int i=0; int j= array.length-1; while(i<j){ int t=array[i]; array[i]=array[j]; array[j]=t; i++; j--; } } public static void main(String[] args) { int[] array ={1,2,3,4,5}; reverse(array); System.out.println(Arrays.toString(array));; }
运行结果
8.通过函数比较两数组值是否一样
Arrays.equals(数组名1,数组名2);
代码实现
public static void main(String[] args) { int[] array1 = {1,2,3,14,5,6}; int[] array2 = {1,2,3,4,5,6}; System.out.println(Arrays.equals(array1, array2)); reverse(array1); System.out.println(Arrays.toString(array1)); System.out.println(Arrays.equals(array1, array2)); }
运行结果
9.局部填充部分数组
Arrays.fill函数
代码实现
public static void main(String[] args) { int[] array=new int[10]; Arrays.fill(array,1,3,99);//左闭右开 System.out.println(Arrays.toString(array)); }
运行结果
10.冒泡排序
思路
两重for循环,为避免排序成功后继续遍历,加入一个boolean类型的变量,最终排序成功后进行输出
代码实现
public static void main(String[] args) { int[] arr={8,12,9,10,6}; //i比较的是趟数 for (int i = 0; i < arr.length-1; i++) { //避免以及排序正确后还要继续排序 boolean flg=false; for (int j = 0; j < arr.length-i-1; j++) { if (arr[j] >= arr[j+1]) { int t=arr[j]; arr[j]=arr[j+1]; arr[j+1]=t; flg=true; } } //避免排序后还要继续排序 if(flg==false){ return; } } System.out.println(Arrays.toString(arr)); }
运行结果
二、二维数组
二维数组本质上也是一维数组,只不过每个元素又是一个一维数组
基本语法
数据类型[][] 数组名称 = new 数据类型[行数][列数]{初始化数据};
int[][] array={{1,2,3},{4,5,6}}; int[][] array2=new int [5][4];//默认初始化为0 int[][] array3=new int[][]{{1,2,3},{4,5,6}};
二维数组是一个特殊的一维数组
二维数组的存储形式
二维数组可以省略行,可以省略列,C语言可以省略行员,Java可以省略列
三种定义方式
int[][] array = {{1, 2, 3}, {4, 5, 6}}; //二维数组可以省略行,可以省略列,C语言可以省略行员,Java可以省略列 int[][] array2 = new int[5][4];//默认初始化为0 int[][] array3 = new int[][]{{1, 2, 3}, {4, 5, 6, 7}};
不规则的二维数组
array4[0]=new int[2]; array4[1]=new int[2]; array4[2]=new int[5];
数组名.length求数组列数
数组名[列数].length 求数组列数
两层for循环,遍历二维数组
for (int i = 0; i < array4.length; i++) { for (int j = 0; j < array4[i].length; j++) { System.out.print(array4[i][j] + " "); } System.out.println(); }
for each遍历
代码实现
//for each遍历 for (int[] tmpArray : array) { System.out.println(tmpArray); for (int x : tmpArray) { System.out.print(x + " "); } System.out.println(); } //打印二维数组 String ret= Arrays.deepToString(array); System.out.println(ret);
运行结果
Arrays函数打印二维数组
语法
Arrays.deepToString(数组名);
代码实现
//打印二维数组 String ret= Arrays.deepToString(array); System.out.println(ret);
运行结果