目录
1.数组基本的用法
1.1什么是数组
数组本质上就是让我们能 "批量" 创建相同类型的变量.
1.2.数组的创建
动态初始化:数据类型[] 数组名称 = new 数据类型 [] { 初始化数据 };
例如: int[ ] data = new int[ ]{ 1,3,5 };
int[ ] data = new int[3];
静态初始化:数据类型[] 数组名称 = { 初始化数据 };
例如: int[ ] data = {1,3,5,7};
1.3.数组的访问和长度
获取数组长度: 数组名称.length
例如:int[ ] data = {1,3,5,7};
data.length可以获取data长度为4.
访问数组中的元素:数组名称[ index] index->索引(0-n-1).
data[2]=5;
注意:访问时不能超出数租长度,index范围为[0,n-1].否则执行报错。
1.4数组的遍历
遍历是指将数组中的所有元素都访问一遍, 不重不漏. 通常需要搭配循环语句.
使用for循环遍历
int[] arr = {1, 2, 3};
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
使用for-each循环遍历
int[] arr = {1, 2, 3};
for (int x : arr) {
System.out.println(x);
}
for-each 是 for 循环的另外一种使用方式. 能够更方便的完成对数组的遍历. 可以避免循环条件和更新语句写错.
注意:如果只遍历,不修改数组中的元素,可以用for-each循环.如果有更改操作使用for循环。
2.数组作为方法的参数
2.1基本用法
public static 返回值类型 方法名(int[ ] a){方法内容}
示例:
public static void main(String[] args) {
int[] arr = {1, 2, 3};
printArray(arr);
}
public static void printArray(int[] a) {
for (int x : a) {
System.out.println(x);
}
}
其中int[]a 是函数的形参, int[] arr 是函数实参.
2.2理解数组引用类型**(重点)
在主函数与方法函数中:修改方法中形参 x 的值, 不影响主函数实参的 num 值.
public static void main(String[] args) {
int num = 0;
fan(num);
System.out.println("num = " + num); //num=0
}
public static void fan(int x) {
x = 10; System.out.println("x = " + x); //x=10
}
参数传数组类型
在函数内部修改数组内容, 函数外部也发生改变.
此时数组名 arr 是一个 "引用" . 当传参的时候, 是按照引用传参.
public static void main(String[] args) {
int[] arr = {1, 2, 3};
fan(arr);
System.out.println("arr[0] = " + arr[0]); arr[0]=10
}
public static void func(int[] a) {
a[0] = 10;
System.out.println("a[0] = " + a[0]); //a[0]=10
}
这关系到内存:
什么是引用:引用就是给实实在在存在的实体起了个名字。
引用数据类型内部保存的都是一块地址数值。
例如:人->实体
名字->引用
2.4认识JVM内存区域划分(重要,写不出)。
3.数组作为方法的返回值
命名:public static int[ ] 方法名(参数){方法内容}
public static int[] fan(int[] arr) {
int[] ret = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
ret[i] = arr[i] * 2;
}
return ret;
}
其中ret[ ]为新的一个数组,指向新的地址。这样的话就不会破坏原有数组了. 另外由于数组是引用类型, 返回的时候只是将这个数组的首地址返回给函数调用者, 没有拷贝数组内容, 从而比较高效.
4.数组常用到的一些方法
4.1转字符串:
Arrays.toString
String string = Arrays.toString(arr) // 也可以自己尝试写一个方法实现
4.2拷贝数组:
Arrays.copyOf(),Arrays.copyOfRange()
int[ ] arr = Arrays.copyOf(原数组名,拷贝后新的数组长度).//也可以自己尝试 写一个方法实现
int[ ] arr = Arrays.copyOf(原数组名,起始位置,结束位置)//左闭右开
深浅拷贝:
深:常见新对象,将原数组复制给新数组。
浅:实际没有创建新数组,只是整了新数组引用。
4.3二分查找
前提:在有序的集合中
每次与中间比,区间变为原数组1/2,到区间只剩最后一个为止。
代码实现:
public static int findNumber(int[] arr, int tofind, int left, int right) {
int mid = (left + right) / 2;
if (left > right) {
return -1;
}
if (tofind == arr[mid]) {
return mid;
} else if (tofind > arr[mid]) {
return findNumber(arr, tofind, mid + 1, right);
} else {
return findNumber(arr, tofind, left, mid - 1);
}
}
时间复杂度为:logn
外扩:当一个算法不断除以一个数,这个算法的数量级为logn
应用:500万数中找元素
1.先使用数组快排,Arrays.sort()
2.在使用二分。
4.3判断数组是否有序
public static boolean isSwaoed(int[] arr) {
for (int j = 0; j < arr.length - 1; j++) {
if (arr[j] > arr[j + 1]) {
return false;
}
}
return true;
}
4.4排序(“冒泡排序”)
Arrays.sort()--->双轴快排
冒泡排序:从第一个元素开始两两比较,将大的放在后边,每走一次可把较大元素放在最终位置。
普通代码:
public static void bubbleSort(int[] arr) {
// [0, bound) 构成了一个前闭后开区间, 表示已排序区间
// [bound, length) 构成了一个前闭后开区间, 表示待排序区间
// 每循环一次, 就找到一个合适大小的元素, 已排序区间就增大1.
for (int bound = 0; bound < arr.length; bound++) {
for (int cur = arr.length - 1; cur > bound; cur--) {
if (arr[cur - 1] > arr[cur]) {
int tmp = arr[cur - 1];
arr[cur - 1] = arr[cur];
arr[cur] = tmp; }
}
}// end for
} // end bubbleSort
优化:添加boolean 变量 在循环中确定数组是否提前完成排序,退出循环
public static int[] maoPao(int[] arr) {
for (int i = 0; i < arr.length; i++) {
boolean isSwaped = true;//每排一趟重置isSwaped
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;
isSwaped = false;
}//if语句如果未执行,则说明在这一趟中,并未产生交换,数组有序
}
if (isSwaped) {
break;
}//isSwaped==true 结束循环,排序完成
}
return arr;
}
4.5数组逆序
public static void reverse(int[] arr) {
int left = 0;
int right = arr.length - 1;
while (left < right) {
int tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
}
5.二维数组 (了解即可)
int[ ][ ] arr = new int[行数][列数];