数组
数组
1 数组的概念
1.1 数组的作用
- 用来保存、管理一组相同数据类型的数据
1.2 把一组具有相同数据类型的变量使用同一个名字来进行管理,并且这些元素按照一定的顺序进行排列。这同一个名字我们称为【数组名】,每一个元素通过编号进行区别,这个编号我们称为【下标】或索引。元素的总个数就是【数组的长度】。
2 数组如何声明和初始化
2.1 数组的声明
-
数组的类型 数组名;
-
数组的元素的类型[] 数组名;
- 推荐的方式
-
数组的元素的类型 数组名[];
2.2 初始化
-
动态初始化
-
格式:
- 数组名 = new 元素的类型[数组的长度];
-
-
静态初始化
-
格式
-
数组名 = new 元素的类型[]{元素列表};
- 元素列表的每一个元素使用,分割
- 元素列表的个数就是数组的长度
-
简写形式
-
数组的元素的类型[] 数组名 = {元素列表};
- 只有声明和静态初始化在一行,才可以这么简写
-
-
-
3 数组的元素
3.1 表示形式
-
数组名[下标]
-
下标的范围
-
[0,数组的长度-1]
- [0, 数组名.length -1]
-
[0,数组的长度)
-
-
3.2 赋值
- 数组名[下标] = 值;
4 数组的长度
4.1 数组名.length
5 数组的遍历
5.1 for循环
- for(int i=0; i<数组名.length; i++){ }
5.2 foreach循环
- for(数组的元素的类型 元素的临时名 : 数组名){ }
6 数组的算法
6.1 (1)在数组中找最大值/最小值
//找最大值
public static int max(int[] arr){
//第一步:假设第一个元素最大
int max = arr[0];
//遍历后面的元素和max比较
for (int i = 1; i < arr.length; i++) {
//当有比max的值,就把max修改为它的值
if(max < arr[i]){
max = arr[i];
}
}
return max;
}
6.2 (2)在数组中找最大值、最小值的下标
//找最大值的下标
public static int maxIndex(int[] arr){
//第一步:假设第一个元素最大
int index = 0;
//arr[index] 和 后续的元素一一比较
for (int i = 1; i < arr.length; i++) {
//当有比max的值,就把max修改为它的值
if(arr[index] < arr[i]){
index = i;
}
}
return index;
}
6.3 (3)数组元素的累加和,平均值
//求数组元素的总和
public static long sum(int[] arr){
long sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum;
}
public static double avg(int[] arr){
double sum = sum(arr);
return sum/arr.length;
}
6.4 (4)反转
//反转
public static void reverse(int[] arr){
//如果有5个元素,应该交换2次或3次 arr.length/2
//如果有6个元素,应该交换3次 arr.length/2
//数组的收尾对应位置交换
//次数
for(int i=0; i<arr.length/2; i++){
//首尾交换
int temp = arr[i];
arr[i] = arr[arr.length-1-i];
arr[arr.length-1-i] = temp;
}
}
//反转部分
public static void reverse(int[] arr, int start ,int end){
//次数
//假设start = 1, end = 5 次数2次 (end + 1 - start)/2 (5+1-1)/2 2
//假设start = 1, end = 6 次数3次 (end + 2 - start)/2 (6+1-1)/2 3
for(int i=0; i< (end + 1 - start)/2; i++){
//首尾交换
//arr[start],arr[start+1]...
//arr[end],arr[end-1]...
int temp = arr[start + i];
arr[start + i] = arr[end -i];
arr[end-i] = temp;
}
}
6.5 (5)复制
//复制一个数组,从原数组的[0]元素开始复制,新数组的长度由使用者决定
public static int[] copy(int[] src, int newLength){
//1、创建新数组的对象
int[] newArray = new int[newLength];
//2、把原数组的元素复制到新数组中
for(int i=0; i<newArray.length && i<src.length; i++){
newArray[i] = src[i];
}
return newArray;
}
//复制一个数组,从原数组的[start]元素开始复制,新数组的长度由使用者决定
public static int[] copy(int[] src, int start, int newLength){
//1、创建新数组
int[] newArray = new int[newLength];
//2、把原数组的元素从[start]复制到新数组的[0]...
for(int i=0; i<newArray.length && start+i<src.length; i++){
newArray[i] = src[start+i];
}
return newArray;
}
6.6 (6)排序
-
冒泡排序
//假设数组5个元素
public static void pubSort3(int[] arr){
//方式二:把大的往右沉 //每一轮从左边开始比较 //比较的轮数依然是n-1轮 for(int i=1; i<arr.length; i++){ //每一轮从左边开始比较 /* * 第一轮:i=1, 比较4次,j=0,1,2,3 ,j<arr.length-i j<5-1 j<4 * 第二轮:i=2,比较3次,j=0,1,2 ,j<arr.length-i j<5-2 j<3 * ... */ for(int j=0; j<arr.length-i; j++){ //如果左边的元比右边的元素大,交换 if(arr[j] > arr[j+1]){ int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } }
}
//假设数组5个元素
public static void pubSort2(int[] arr){
//排序规则:每一轮通过相邻元素的比较,把小的往左边冒(或把大的往右边沉),每一轮都是把本轮的最小值冒出来(最大值沉下去) //经过n-1轮完成最终的排序 //(1)方式一:把小的往左边冒,注意,每一轮都是从最右边往左边比较 //i=0,i=1,i=2,i=3 i<5-1 --> i<4 --> i<=3 for(int i=0; i<arr.length-1; i++){//一共n-1轮 //每一轮都要从最右边往左边比较 /* * 第一轮:比较n-1次,比较4次, i=0, j=4,3,2,1 ,j>i * 第二轮:比较3次,i=1, j=4,3,2 ,j>i * .... */ for(int j=arr.length-1; j>i; j--){ //相邻的元素比较,而且如果右边的比左边的小,需要交换 if(arr[j] < arr[j-1]){ int temp = arr[j]; arr[j] = arr[j-1]; arr[j-1] = temp; } } }
}
//冒泡排序:从小到大
//如果数组是5个元素
public static void pubSort(int[] arr){
//排序规则:每一轮通过相邻元素的比较,把小的往左边冒(或把大的往右边沉),每一轮都是把本轮的最小值冒出来(最大值沉下去) //经过n-1轮完成最终的排序 //(1)方式一:把小的往左边冒,注意,每一轮都是从最右边往左边比较 for(int i=1; i<arr.length; i++){//一共n-1轮 //每一轮都要从最右边往左边比较 /* * 第一轮:比较n-1次,比较4次, i=1, j=4,3,2,1 ,j>=i * 第二轮:比较3次,i=2, j=4,3,2 ,j>=i * .... */ for(int j=arr.length-1; j>=i; j--){ //相邻的元素比较,而且如果右边的比左边的小,需要交换 if(arr[j] < arr[j-1]){ int temp = arr[j]; arr[j] = arr[j-1]; arr[j-1] = temp; } } }
}
-
直接选择排序
//直接选择排序
//基本原理:将待排序的元素分为已排序(初始为空)和未排序两组,依次将未排序的元素中值最小的元素放入已排序的组中。
//[3,2,1,5,4] 从小到大排序
/*
* 第一次:所有元素都属于未排序 把未排序的元素中的最小值找出来 arr[2] = 1 ,放入已排序组中 和第一个元素交换
* [1,2,3,5,4]
* 第二次:已排序的是[1],未排序的是[2,3,5,4],把未排序元素中的最小值找出 arr[1]=2,放入已排序组中
* 【1,2】,【3,5,4】
* …
*
*/
//假设5个元素
public static void selectSort(int[] arr){
//次数 for(int i=0; i<arr.length-1; i++){ //第一次,找最小值 //假设每一轮的未排序元素的第一个最小 int index = i; //找出本轮最小值 /* * int i=0 ,从哪些元素中找最小值 [0]~[4] j=1,2,3,4 * int i=1,从哪些元素中找最小值[1]~[4] j=2,3,4 * ... */ for(int j=i+1; j<arr.length; j++){ if(arr[index] > arr[j]){ index = j; } } //找出arr[index]值最小,下标是index //arr[i] 和 arr[index]交换 if(i!=index){ int temp = arr[i]; arr[i] = arr[index]; arr[index] = temp; } }
}
6.7 (7)数组的扩容
private void kuorong(){
//先扩容
int[] newArray = new int[arr.length*2];
//通过循环把原数组中的内容复制到新数组中
for(int i=0; i<arr.length; i++){
newArray[i] = arr[i];
}
//把新家的地址记录下来,下次存、取元素都从新家操作,旧家不要了
arr = newArray;
}
6.8 (8)数组的元素插入
package com.atguigu.array;
public class MyArrayList {
private int[] arr = new int[5];//装数据
private int total;//记录实际存储的元素的个数
//在index插入数据data
public void insert(int index, int data){
//如果当前数组已满,需要先扩容
if(total >= arr.length){
//(1)先创建一个新的更大的数组
int[] newArray = new int[arr.length*2];
//(2)把原来数组中的数据复制到新数组中
for(int i=0; i<arr.length; i++){
newArray[i] = arr[i];
}
//(3)使得arr指向新数组
arr = newArray;
}
//1、先把index右边的元素右移
/*
* 假设total=3,index=1
* 现在有值arr[0],arr[1],arr[2],需要移动的是arr[2],arr[1]
* 假设total=5,index=1
* 现在有值arr[0],arr[1],arr[2],arr[3],arr[4],需要移动的是,arr[4],arr[3],arr[2],arr[1]
*/
for(int i = total-1; i>=index; i--){
//右边的元素=左边的元素
arr[i+1] = arr[i];
}
//在index位置插入data
arr[index]= data;
//元素个数加1
total++;
}
}
6.9 (9)数组的元素删除
-
删除指定位置的元素
package com.atguigu.array;
public class MyArrayList {
private int[] arr = new int[5];//装数据
private int total;//记录实际存储的元素的个数
//删除指定位置的元素
public void delete(int index){
//(1)把index右边的元素左移 /* * 假设现在total=3,index =1 * 有值的是arr[0],arr[1],arr[2],需要移动的是arr[2] * 假设现在total=5,index =1 * 现在有值arr[0],arr[1],arr[2],arr[3],arr[4],需要移动的似乎arr[2],arr[3],arr[4] */ for(int i = index+1; i<total; i++){ //左边的元素=右边的元素 arr[i-1] = arr[i]; } //(2)把最后一个元素的位置置为“空”(还原到默认值) arr[total-1] = 0; //(3)元素个数减一 total--;
}
}
-
删除指定的元素值
package com.atguigu.array;
public class MyArrayList {
private int[] arr = new int[5];//装数据
private int total;//记录实际存储的元素的个数
//删除指定位置的元素
public void delete(int index){
//(1)把index右边的元素左移 /* * 假设现在total=3,index =1 * 有值的是arr[0],arr[1],arr[2],需要移动的是arr[2] * 假设现在total=5,index =1 * 现在有值arr[0],arr[1],arr[2],arr[3],arr[4],需要移动的似乎arr[2],arr[3],arr[4] */ for(int i = index+1; i<total; i++){ //左边的元素=右边的元素 arr[i-1] = arr[i]; } //(2)把最后一个元素的位置置为“空”(还原到默认值) arr[total-1] = 0; //(3)元素个数减一 total--;
}
public int findValue(int value){
//挨个遍历,一共有total,遍历total个 for (int i = 0; i < total; i++) { if(arr[i] == value){ return i; } } return -1;
}
public void deleteValue(int value){
//1、先找到value在数组中的index,这里以第一次找到为准 int index = findValue(value); //2、删除index位置的元素 if(index!=-1){ delete(index); }
}
}
6.10 (10)在数组中查找某个值的下标
package com.atguigu.array;
public class MyArrayList {
private int[] arr = new int[5];//装数据
private int total;//记录实际存储的元素的个数
//删除指定位置的元素
public void delete(int index){
//(1)把index右边的元素左移
/*
* 假设现在total=3,index =1
* 有值的是arr[0],arr[1],arr[2],需要移动的是arr[2]
* 假设现在total=5,index =1
* 现在有值arr[0],arr[1],arr[2],arr[3],arr[4],需要移动的似乎arr[2],arr[3],arr[4]
*/
for(int i = index+1; i<total; i++){
//左边的元素=右边的元素
arr[i-1] = arr[i];
}
//(2)把最后一个元素的位置置为“空”(还原到默认值)
arr[total-1] = 0;
//(3)元素个数减一
total--;
}
public int findValue(int value){
//挨个遍历,一共有total,遍历total个
for (int i = 0; i < total; i++) {
if(arr[i] == value){
return i;
}
}
return -1;
}
public void deleteValue(int value){
//1、先找到value在数组中的index,这里以第一次找到为准
int index = findValue(value);
//2、删除index位置的元素
if(index!=-1){
delete(index);
}
}
}
7 二维数组
7.1 如何声明
-
数组类型 数组名;
- 数组类型是xx[][]
-
元素的类型[][] 数组名;
7.2 如何创建二维数组对象及初始化
-
动态初始化
-
数组名 = new 元素的数据类型[行长度][每一行的列长度];
- 每一行的列数相同
-
数组名 = new 元素的数据类型[行长度][];
-
每一行的列数不确定
-
每一行的行对象暂时是null
-
创建每一行的行对象,即为行分配空间
- 数组名[行下标] = new 元素的类型[该行的列数];
-
-
-
静态初始化
-
数组名 = new 元素的数据类型[][]{{x,x,x,x,….},{x,x,x},{x,x,x,x,x,x,x},…..};
- {}中嵌套{},里面的一个{}代表一行
-
7.3 二维数组的长度,即行数
- 二维数组名.length
7.4 二维数组的行对象
-
二维数组名[行下标]
- 行下标的范围[0,二维数组名.length-1]
7.5 二维数组的每一行的列数
- 二维数组名[行下标].length
7.6 二维数组的每一个元素
-
二维数组名[行下标][列下标]
-
注意列下标
- 每一行的列下标的范围可能是不一样
- [0, 二维数组名[行下标].length)
-
-
二维数组名[行下标][列下标] = 值
7.7 二维数组的遍历
-
for
- for(int i=0; i<数组名.length; i++){ for(int j=0; j<数组名[i].length; j++){ 数组名[i][j]表示一个元素 } }
-
增强for
- for(行类型 hang : 二维数组名){ for(元素类型 lie : hang){ lie就是代表每一个元素 } }
8 数组的内存图
8.1 一维数组
-
元素是基本数据类型
-
元素是引用数据类型,又称为对象数组
8.2 二维数组
-
元素是基本数据类型
-
规则
-
不规则
-
-
元素是引用数据类型
-
规则
-
不规则
-
9 数组的工具类
9.1 java.util.Arrays
9.2 静态方法
-
(1)int Arrays.binarySearch(int[] a ,int key)
- 在a数组中查找key的下标
- (1)数组a必须是有序的,否则结果不一定正确
- (2)如果key在a中存在,就返回它的下标,如果不存在,返回(-(插入点)-1)
-
(2)Arrays.fill(int[] a, int value)
- 给数组a的每一个元素都赋值为value
-
(3)Arrays.sort(int[])
- 排序,从小到大
-
(4)String Arrays.toString(int[] a)
- 把数组的元素列表用字符串返回,形式[元素1,元素2,元素3.。。]
10 命令行参数
10.1 主方法的参数
10.2 java命令
-
java 包.类名 参数1 参数2 参数3 ….
- 参数之间使用空格
10.3 eclipse
11 可变参数
11.1 可变参数属于形参
11.2 要求
- 一个方法只能有一个可变参数,而且只能是最后一个
- 在声明它的方法中,当做数组处理
- 对于调用这个方法者,可变参数的位置可以传,[0~n]个实参,也可以传对应类型数组对象
11.3 可变参数的重载问题
-
对于编译器来说不属于重载
-
不属于重载
- public static void main(String[] args) { System.out.println(getSum(1)); }
public static int getSum(int… args){ return 0; } public static int getSum(int a,int… args){ return 0; }
- 如果传一个整数时,不知道用谁好 - public static int getSum(int... args){ return 0;
}
public static int getSum(int[] args){
}
- 但是它俩不完全等价 - 因为int... args既可以传数组对象,又可以传 n个元素值 - int[]只能传数组对象
-
属于重载
- public static void main(String[] args) { System.out.println(getSum(1)); }
public static int getSum(int… args){ return 0; } public static int getSum(int a){ System.out.println(“一个参数”); return 0; }
- 优先于确定参数个数
-