数组
数组的定义
数组是一个数据容器,可以存储基本数据类型,也可以存储引用数据类型的数据;数组的长度是不可变的,数组的内存空间是连续的;一个数组一旦实例化完成,长度是不能够改变的。
数组的声明
int[] arr1 = new int[5];//java语言风格
int arr2[] = new int[5];//C系语言风格
int[] arr3 = new int[] {1,2,3,4,5}
int[] arr4 = {1,2,3,4,5}
数组引用
数组的实例化的时候, 需要使用到关键字new.
数组, 其实是在堆上开辟的连续的空间。 例如 new int[5] , 就是在堆上开辟5个连续的4字节空间。
然后, 将堆上的内存地址, 赋值给栈上的变量array(引用)。
- 内存地址扩展说明
关于数组中地址和值的说明:
- 引用地址(包括数组地址),是一个十六进制的数。
- 在内存的堆中,是连续的空间,上图中的数组中一共5个元素,每一个4个字节,数组的每个元素都有自己的地址,我们得到第一个后,根据元素所占内存可以推算出后面的地址。
- 数组第一个元素比较特殊,它的地址同时还是整个数组的地址
数组的下标
下标:就是数组中的元素在数组中存储的位置索引。
注意:数组的下标是从0开始的, 即数组中的元素下标范围是 [0, 数组.length - 1]
通过下标进行数组元素访问:
public class Test {
public static void main(String[] args) {
// 实例化一个数组
int[] array = { 1, 2, 3, 4, 5 };
// 访问数组中的元素
array[2] = 300; // 将数组中的第2个元素修改成300, 此时
数组中的元素是 [ 1, 2, 300, 4, 5 ]
System.out.println(array[2]); // 获取数组中的第2个元素, 此时的输出结果是 300
}
}
- 注意:在访问数组中的元素的时候, 注意下标的问题,使用错误的下标访问数组中的元素, 将会出现 ArrayIndexOutOfBoundsException异常
通过增强for循环进行数组元素访问:
public class Test {
public static void main(String[] args) {
// 实例化一个数组
int[] array = { 1, 2, 3, 4, 5 };
// 依次使用数组中的每一个元素, 给迭代变量进行赋值。
// 此时, 数组中的每一个元素依次给 element 进行赋值。
for (int element : array) {
System.out.println(element);
}
}
}
两种遍历方式的对比:
- 如果需要在遍历的同时, 获取到数组中的元素下标, 需要使用下标遍历法。
- 如果需要在遍历的同时, 修改数组中的元素, 需要使用下标遍历法。
- 如果仅仅是想要获取数组中的每一个元素, 不需要下标, 也不需要修改数组中的元素,使用增强for循环。 因为这种方式, 遍历的效率比下标遍历法高。
函数和数组的联合应用
函数传参分类
- 值传递:将保存简单数据的变量作为参数传递
- 址传递:将保存地址的变量作为参数传递
- 址传递优点:让我们可以实现使用一个变量一次传递多个值
public class Demo3 {
public static void main(String[] args) {
//求三个数的和
//直接用数值作为参数传递-值传递
int tmp1 = getMax(3, 4, 6);
System.out.println(tmp1);
//用数组实现求三个数的和-址传递
int[] arr1 = new int[] {3,5,8};
int tmp2 = getMax(arr1);
System.out.println(tmp2);
}
public static int getMax(int a,int b,int c) {//值传递
int tmp = a>b?a:b;
return c>tmp?c:tmp;
}
public static int getMax(int[] arr) {//地址传递 arr = arr1
int max = arr[0];
for (int i=0;i<arr.length-1;i++) {
if (max < arr[i+1]) {
max = arr[i+1];
}
}
return max;
}
}
值传递和址传递比较:
通过值作为参数传递,函数内部值的变化不会改变外部的值。
通过地址作为参数传递,函数内部值的变化可以直接改变外部值。
public class Demo4 {
public static void main(String[] args) {
//交换两个数的值
int[] temp = {3,5};
//地址传递
jiaohuan1(temp);
//我们发现通过址传递数组temp内的两个值发生了交换
System.out.println("temp[0]:"+temp[0]+" temp[1]:"+temp[1]);// 5
3
//值传递
int[] temp1 = {3,5};
jiaohuan2(temp1[0], temp1[1]);
//通过值传递数组temp内的两个值没有发生交换
System.out.println("temp1[0]:"+temp1[0]+"
temp1[1]:"+temp1[1]);// 3 5
}
//地址传递
public static void jiaohuan1(int[] arr) {
arr[0] = arr[0] ^ arr[1];
arr[1] = arr[0] ^ arr[1];
arr[0] = arr[0] ^ arr[1];
}
//值传递
public static void jiaohuan2(int a,int b) {
a = a ^ b;
b = a ^ b;
a = a ^ b;
}
}
总结:址传递的最终原因是两个变量保存了同一个数组的地址,操作的是同一个数组。
可变长参数
概念:
可以接收多个类型相同的实参,个数不限,使用方式与数组相同。
在调用方法的时候, 实参的数量可以写任意多个。
作用:简化代码,简化操作等
语法:
// 这里的参数paramters其实就是一个数组
static void show(int... parameters) {
//
}
例子:
public static int sum1(int... a){
int sum=0;
for (int i = 0; i < a.length; i++) {
sum+=a[i];
}
return sum;
}
数组的排序
冒泡排序
//BubbleSort
public static void bubble(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
boolean flag = true;
for (int j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j+1]) {//升序
//使用位异或交换
arr[j] ^= arr[j+1];
arr[j+1] ^= arr[j];
arr[j] ^= arr[j+1];
flag = false;
}
}
if (flag) {
break;
}
}
}
选择排序
//SelectedSort
public static void selectedSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
int minIndex = i;
for (int j = i + 1; j < arr.length; j++) {
if (arr[minIndex] > arr[j]) {
minIndex = j;
}
}
if (minIndex != i ){
arr[i] ^= arr[minIndex];
arr[minIndex] ^= arr[i];
arr[i] ^= arr[minIndex];
}
}
}
数组的查询
线性查询
顺序查询, 即遍历数组中的每一个元素, 和要查询的元素进行对比。 如果是要查询的元素,这个下标就是要查询的下标。
查询三要素:
- 我们只找查到的第一个与key相同的元素,查询结束。
- 当查询到与key相同的元素时,返回元素的下标。
- 如果没有查询到与key相同的元素,返回-1。
//LinerSearch
public static int linerSearch(int[] arr, int number) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] == number) {
return i;
}
}
return -1;
}
二分查询
注: 使用二分查询的前提是,待查询的数组必须是有序的
二分查询: 即利用数组中间的位置, 将数组分为前后两个字表。 如果中间位置记录的关键字
大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到
找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。
//BinarySearch
public static int binarySearch(int[] arr, int number, int left, int right) {
if (left > right) {
return -1;
}
int mid = (left + right) / 2;
if (arr[mid] > number) {
return binarySearch(arr, number, left, mid-1);
} else if (arr[mid] < number) {
return binarySearch(arr, number, mid+1, right);
} else {
return mid;
}
}
二维数组
定义:
二维数组, 其实就是数组中嵌套数组。也就是二维数组中的每一个元素都是一个小的数组。理论上来讲, 还可以有三维数组、四维数组, 但是常用的其实就是二维数组。
定义和使用:
public class Array1 {
public static void main(String[] args) {
int[] arr = new int[3];
// 1. 实例化一个二维数组
// 第一个中括号中的3: 二维数组中包含了三个一维数组
// 第二个中括号中的5: 二维数组中的每一个一维数组长度为5
int[][] array1 = new int[3][5];
// 使用双下标访问数组中的元素
array1[0][3] = 10;
// 这里得到的,是二维数组的长度,3
System.out.println(array1.length);
// 2. 实例化一个二维数组
// 第一个中括号中的3: 二维数组中包含了三个一维数组
// 第二个中括号中什么都没有,代表现在二维数组中的三个元素是 null
int[][] array2 = new int[3][];
array2[0] = new int[] { 1, 2, 3 };
// 3. 通过初始值实例化一个二维数组
int[][] array3 = { {1, 2, 3}, {1, 2, 3, 4, 5}, {2, 3, 4} };
// 4. 二维数组的遍历
for (int i = 0; i < array3.length; i++) {
for (int j = 0; j < array3[i].length; j++) {
System.out.print(array3[i][j] + " ");
}
}
}
}
(补充)常用的数组工具类Arrays
方法 | 描述 |
---|---|
copyOf(int[] array, int newLength) | 从原数组中拷贝指定数量的元素,到一个新的数组中,并返回这个新的数组 |
copyOfRange(int[] array, int from, int to) | 从原数组中拷贝指定范围 [from, to) 的元素,到一个新的数组中,并返回这个新的数组 |
equals(int[] array1, int[] array2) | 判断两个数组是否相同 |
fill(int[] array, int element) | 使用指定的数据,填充数组 |
sort(int[] array) | 对数组进行排序(升序) |
binarySearch(int[] array, int element) | 使用二分查找法,到数组中查询指定的元素出现的下标 |
toString(int[] array) | 将数组中的元素拼接成字符串返回 |
- 测试代码
import java.util.Arrays;
public class ArraysUse {
// Arrays 工具方法: 可以便捷的实现指定操作的方法
// Arrays 工具类: 若干个工具方法的集合
public static void main(String[] args) {
// 1. 实例化一个数组
int[] array = { 1, 3, 5, 7, 9, 0, 8, 6, 4, 2 };
// 从原数组中拷贝指定数量的元素,到一个新的数组中,并返回这个新的数组
// 第一个参数:源数组
// 第二个参数:需要拷贝的元素数量,如果这个数量比源数组长,目标数组剩余的部分补默认值
int[] ret1 = Arrays.copyOf(array, 13);
// 从原数组中拷贝指定范围 [from, to) 的元素,到一个新的数组中,并返回这个新的数组
// 第一个参数:源数组
// 第二个参数:起始下标,从这个下标位的元素开始拷贝
// 第三个参数:目标下标,拷贝到这个下标位截止
int[] ret2 = Arrays.copyOfRange(array, array.length, array.length + 10);
// 判断两个数组是否相同
// 判断的逻辑:长度、每一个元素依次都相等
boolean ret3 = Arrays.equals(ret1, ret2);
// 使用指定的数据,填充数组
// 第一个参数:需要填充的数组
// 第二个参数:填充的数据
Arrays.fill(ret2, 100);
// 对数组进行排序(升序)
Arrays.sort(array);
// 使用二分查找法,到数组中查询指定的元素出现的下标
// 第一个参数:需要查询的数组
// 第二个参数:需要查询的数据
// 返回:这个元素出现的下标,如果不存在,返回-1
int index = Arrays.binarySearch(array, 4);
// 将数组中的元素拼接成字符串返回
String str = Arrays.toString(array);
System.out.println(str);
}
}