文章目录
- 8、数组
- 8.1 一维数组
- 8.1.1 定义数组的格式
- 8.1.2 数组的基本操作
- 8.1.2 数组的遍历——查询数组中所有的元素
- 8.2 数组的高级操作
- 8.3 二维数组
- 8.3.1 概念
- 8.3.2 格式
- 8.3.3 二维数组的使用
- 8.3.4 二维数组的应用
8、数组
在Java中数组属于引用类型变量,是一种可以存储多个同一数据类型的值的容器,且长度固定、内容可变。
8.1 一维数组
8.1.1 定义数组的格式
1、格式一:
数据类型[] 数组名/变量名 = new 数据类型[数组长度/元素个数];
例:定义一个元素个数为5的数组
int[] nums = new int[5];
特点:该定义格式需要指定数组的长度,不需要赋初始值,但数组元素会有默认值:byte、short、int类型的默认值为0;long类型的默认值为0L(输出为0);float、double类型的默认值为0.0;char类型的默认值为’\u0000’(空格);boolean类型的默认值为false;引用数据类型的默认值为null。
2、格式二:
数据类型[] 数组名 = new 数据类型[]{元素1,元素2……元素n};
例:定义一个元素为1,2,3的数组
int[] nums = new int[]{1,2,3};
特点:该格式在创建数组时直接给元素赋初始值,数组的长度等于元素个数。
3、格式三:
数据类型[] 数组名 ={元素1,元素2……元素n};
例:定义一个元素为1,2,3的数组
int[] nums ={1,2,3};
特点:该格式在创建数组时直接给元素赋初始值,数组的长度等于元素个数,该格式是格式二的简化。
注意:格式一和格式二均可先声明再赋值,但是格式三不可以。
//格式一
int[] nums1 ;
nums1 = new int[3];
nums1[0] = 1;
nums1[1] = 2;
nums1[2] = 3;
//格式二
int[] nums2;
nums2 = new int[]{1,2,3};
//格式三,编译时会报错
int[] nums3 ;
//nums3 = {1,2,3};//编译时会报错
8.1.2 数组的基本操作
1、获取数组的元素
数组创建之后会给每个元素一个编号,即下标/索引。
格式:
数组名[下标编号]
int[] nums = {0,1,2,3};
System.out.println(nums[0]);//输出0下标对应的元素值:0
注意:
(1)下标的取值范围:0~(数组长度-1)
(2)数组下标越界异常:当数组下标超出范围时,编译不会报错,但是运行时会抛出数组下标越界异常(ArrayIndexOutOfBoundsException)
2、设置或者修改数组元素的值
格式:
数组名[下标] = 指定的数据值;
3、获取数组的长度
格式:
数组名.length;
8.1.2 数组的遍历——查询数组中所有的元素
1、方式一:(普通for循环)
格式:
for(int i = 0 ; i < 数组名.length ; i++){
System.out.println(数组名[i]);
}
int[] nums = {0,1,2,3};
for (int i = 0; i < nums.length ; i++) {
System.out.println(nums[i]);
}
运行结果:
0
1
2
3
2、方式二:(增强for循环——foreach)
格式:
for(数据类型 临时变量名 : 要遍历的数组名){
通过临时变量来获取数组当前元素的值;
}
int[] nums = {0,1,2,3};
for (int num : nums) {
System.out.println(num);
}
运行结果
0
1
2
3
注意:
(1)增强for循环只能用于遍历数组、集合、映射;
(2)在增强for循环中,定义的是临时变量(局部变量),for循环结束后就会被释放了;
(3)执行流程:将要遍历的数组中的所有元素按照顺序依次赋值给临时变量。
3、方式三:(使用数组的工具类——Arrays)
格式:
Arrays.toString(数组名);
int[] nums = {0,1,2,3};
System.out.println(Arrays.toString(nums));
运行结果
[0, 1, 2, 3]
三种方式的对比:
(1)如果只是要查询数组所有元素的值,用方式三简单方便;但是该方式不灵活,通常用于开发期间测试、错误调试、数组转字符串等场景;
(2)方式一是最灵活的,可以通过下标来操作数组中的指定元素;
(3)方式二:通常只用于获取数组的元素值,但是因为这种方式无法获取数组的下标,所以无法修改数组的元素值,一般不用于增删改,只能查
8.2 数组的高级操作
1、获取数组的最大/小值
int[] nums = {2,5,7,1,9};
int max = nums[0];
for (int i = 0; i < nums.length; i++) {
if (max < nums[i]){
max = nums[i];
}
}
System.out.println("最大值为:" + max);
2、获取数组中所有元素之和
int[] nums = {2,5,7,1,9};
int sum = nums[0];
for (int i = 1; i < nums.length; i++) {
sum += nums[i];
}
System.out.println("数组中所有元素之和为:" + sum);
3、查找数组中的指定元素
(1)普通查找
int[] nums = {2,5,7,1,9};
int target = 5;
boolean flag = false;
for (int i = 0; i < nums.length ; i++) {
if (target == nums[i]){
flag = true;
System.out.println("查找到" + target + "的下标为" + i);
}
}
if (flag == false){
System.out.println("没找到!");
}
优点:
如果数组中有多个要查找的元素,这种方式均可以获取所有匹配元素的下标,容易理解,容易上手;
缺点:
效率低。
(2)二分查找(折半查找)⭐重点
前提:数组必须是有序的。
设置min、max、mid三个变量,记录下标的变化,初始min = 0 , max = nums.length - 1 , mid = (min+max)/2;用准备查找的数据target和mid下标所对应的数据做比较,若nums[mid] == target,则当前mid即为需要查找数据的下标值;若nums[mid] > target,则将max移到mid前一位,即max = mid - 1;若nums[mid] < target,则将min移到mid后一位,即min = mid + 1。按照上述条件,依次将nums[mid]和target做比较,直到nums[mid] == target为止。原理图如下:
具体代码如下:
int[] nums = {1,3,5,7,8,10,11};
int target = 8;//表示要查找的元素值
int min = 0;
int max = nums.length-1;
int mid = (min + max)/2;
if(target >= nums[min] && target <= nums[max]){
while(true){
if(nums[mid] == target){ //如果目标值和中间值相等,找到了
System.out.println("找到了" + target +"的下标为:" + mid);
break;
}else if(nums[mid] < target){ //目标值大于中间值 目标值在右边
min = mid+1; //最小值移到中间值右边一位
}else{
max = mid -1; //最大值移到中间值左边一位
}
mid = (min+max)/2; //重新计算中间值
if(min >max){ //当最小值大于最大值了,表示目标值不在数组中
System.out.println("没找到");
break; //跳出循环,这里不能缺,否则报错
}
}
}else{
System.out.println("没找到");
}
运行结果:
找到了8的下标为:4
优点:
相对于数据量大的时候,效率高。但是灵活性不高
4、数组排序
(1)冒泡排序
从小到大排序
具体代码如下:
int[] nums = {6,4,2,7,1};
for(int i = 1 ; i <= nums.length-1 ;i++){ // i 表示轮数
//当前表示第i轮的比较
for(int j=0;j<=nums.length-1-i;j++){
// j 表示要比较的两个数的前一个数的下标
if(nums[j] > nums[j+1]){ //从大到小,将条件改为nums[j] < nums[j+1]
//交换位置
int temp = nums[j];
nums[j] = nums[j+1];
nums[j+1] = temp;
}
}
}
System.out.println(Arrays.toString(nums));
运行结果:
[1, 2, 4, 6, 7]
(2)选择排序
代码如下:
int[] nums = {5,2,1,4,3};
for(int i = 1 ; i < nums.length ; i ++){ //轮数
for(int j = i ; j <nums.length ; j ++){ //表示参与比较的两个数中后一个数的下标
// 第一个数:i-1 第二个数:j
if(nums[i-1] >nums[j]){
//交换位置
int temp = nums[i-1];
nums[i-1] = nums[j];
nums[j] = temp;
}
}
}
System.out.println(Arrays.toString(nums));
运行结果:
[1, 2, 3, 4, 5]
5、数组的反转
(1)方式一
遍历数组时,利用for循环根据下标直接倒序遍历。
该方法实现了一次性的倒序输出,不会改变数组本身。
int[] nums = {6,2,5,3,1};
//顺序输出
for(int i = 0 ; i < nums.length ; i ++){
System.out.print(nums[i]);
}
System.out.println();
//逆序输出
for(int i = nums.length-1 ; i >= 0 ; i --){
System.out.print(nums[i]);
}
运行结果
62531
13526
(2)方式二
引入第三个变量,根据下标改变对应的数组值,这个改变是永久性改变,改变了数组本身。
for(int i = 0 ; i <= (nums.length-1)/2 ; i ++){
int temp = nums[i];
nums[i] = nums[nums.length-1-i];
nums[nums.length -1-i] = temp;
}
System.out.println(Arrays.toString(nums));
(3)方式三
和方式二相似
for(int start =0,end=nums.length-1;start>end;start++ ,end--){
int temp = nums[start];
nums[start] = nums[end];
nums[end] = temp;
}
System.out.println(Arrays.toString(nums));
6、数组的扩容
(1) 方法一:
创建一个新的数组,将原来数组的元素拷贝到新的数组中
int[] nums = {6,1,3};
//扩容成6个元素
//定义一个新的数组 长度直接指定
int[] nums1 = new int[6];
for(int i =0;i<nums.length;i++){
nums1[i]=nums[i];
}
nums = nums1;//将nums1的地址赋值给nums,nums就指向了长度为6的数组
System.out.println(Arrays.toString(nums));
(2)方式二
用arraycopy实现:
System.arraycopy(Object src , int srcPos , Object dest , int destPos , int length )
src 原数组对象
srcPos 原数组的起始位置(从哪个元素开始拷贝)
dest目标数组的名称
destPos 目标数组的起始位置
length原数组的长度
注意:src和dest都必须是同类型或者可以进行转换类型的数组.
再看看代码
int[] nums = {6,1,3};
int[] nums1 = new int[6];
//从nums数组的0下标开始,拷贝nums.length长度的数组,从0下标开始拷贝到nums1数组中
System.arraycopy(nums, 0, nums1, 0, nums.length);
nums = nums1;
System.out.println(Arrays.toString(nums));
int[] nums2 = new int[6];
//从nums数组的1下标开始,拷贝1长度的数组,从0下标开始拷贝到nums2数组中
System.arraycopy(nums, 1, nums2, 0, 1);
nums = nums2;
System.out.println(Arrays.toString(nums));
运行结果
[6, 1, 3, 0, 0, 0]
[1, 0, 0, 0, 0, 0]
(3)方式三
用Arrays.copyOf来扩容
Arrays.copyOf(int[] original ,int newLength)
original源数组名称
newLength新数组的长度,可扩容也可缩容
int[] nums = {6,1,3};
nums =Arrays.copyOf(nums,6);
System.out.println(Arrays.toString(nums));
运行结果
[6, 1, 3, 0, 0, 0]
8.3 二维数组
8.3.1 概念
定义一个数组,且数组的每一个元素都是一个一维数组。
8.3.2 格式
1、格式一
数据类型[][] 数组名 = new 数组类型[一维数组的个数][每个一维数组的元素个数];
特点:
在创建二维数组时直接指定了一维数组的个数以及每一个一维数组中元素的个数
2、格式二
数据类型[][] 数组名 = new 数组类型[一维数组的个数][];
数组名[下标] = new 数据类型[当前下标对应的一维数组的元素的个数];//定义每个一维数组内的元素个数
int[][] nums = new int[2][];
nums[0] = new int[3];//或者nums[0] = new int[]{1,2,3};
特点:
在创建二维数组值只指定了一维数组的个数,并没有指定一维数组中包含的元素个数之后可以通过数组名[下标]单独给出该一维组的元素的个数。
3、格式三
数据类型[][] 数组名 = {{元素11,元素12,元素13,……},{元素21,元素22,元素23,……},……};
特点:
在创建二维数组时,直接指定了所有元素值。也确定了一维数组的个数以及每个一维数组中元素的个数(长度)
8.3.3 二维数组的使用
通过下标获取或设置元素的值
若输入:数组名[下标] ;//表示当前下标对应的一维数组,输出该一维数组的地址
数组名[一维数组的下标][元素的下标];//表示输出指定一维数组中的指定元素值
int[][] nums = {{1,2,3},{1,2,3}};
System.out.println(nums[0]);//返回结果:[I@1b6d3586
System.out.println(nums[0][0]);//返回结果:1
8.3.4 二维数组的应用
1、获取数组长度:
(1)获取二维数组中一维数组的个数
数组名.length
(2)获取下标为i的一维数组的元素的个数
数组名[i].length
int[][] nums = {{1,2,3},{1,2,3}};
System.out.println(nums.length);//返回结果:2
System.out.println(nums[0].length);//返回结果:3
2、二维数组的遍历
(1)用普通for循环遍历
int[][] nums = {{1,2,3},{4,5,6}};
for (int i = 0; i < nums.length; i++) { //遍历第i个一维数组
for (int j = 0; j < nums[i].length; j++) { //遍历下标为i的一维数组的所有元素
System.out.print(nums[i][j]);
}
System.out.println();
}
运行结果
123
456
(2)用增强for循环遍历
int[][] nums = {{1,2,3},{4,5,6}};
for (int[] arr :nums) {//将二维数组中一维数组给了一维数组类型的临时变量arr
for (int num : arr) {//将每个一维数组中的元素给了int类型的临时变量num
System.out.print(num);
}
System.out.println();
}
运行结果
123
456