数组
数组是什么
数组, 是一个数据容器。 可以存储若干个相兼容的数据类型的数据。
定义
1.数组中可以存储基本数据类型的数据, 也可以存储引用数据类型的数据。
2.数组的长度是不可变的,数组的内存空间是连续的。 一个数组一旦实例化完成, 长度不能
改变。
比较简单和引用数据类型
1.引用数据类型里面存储的是地址,并且这个地址是十六进制的数.简单数据类型存储的是值,是十进制的。
2.对于简单数据类型,直接在栈区的方法中开辟一块空间存储当前的变量,将要存储的数据直接放在这块空间里。
数组的声明
double[] arr;
int arr = new int[3];
int[] array2 = new int[] { 1, 2, 3, 4, 5 };
int[] array3 = { 1, 2, 3, 4, 5 };
int array3[] = { 1, 2, 3, 4, 5 };
数组的引用
数组实例化的时候,需要使用关键字new
以后但凡是遇到了new 都表示在堆上开辟空间,
然后将堆上的内存地址,赋值给栈上的变量arr(引用)
内存地址说明(扩展)。
1.引用地址(包括数组地址),是一个十六进制的数.
2.在内存的堆中,是连续的空间,上图中的数组中一共5个元素,每一个4个字节,数组的每个元素
都有自己的地址,我们得到第一个后,根据元素所占内存可以推算出后面的地址.
3.数组第一个元素比较特殊,它的地址同时还是整个数组的地址
数组的下标
下标, 就是数组中的元素在数组中存储的位置索引。
注意: 数组的下标是从0开始的, 即数组中的元素下标范围是 [0, 数组.length - 1
访问数组中的元素, 需要使用下标访问。
注意事项
在访问数组中的元素的时候, 注意下标的问题!
如果使用错误的下标访问数组中的元素, 将会出现 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 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]);// 53
//值传递
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;
}
}
内存说明:
1.我们发现在值传递发生过程中,a和b的值在方法jiaohuan2中确实发生了交换,但是并没有影
响到数组的值.
2.在址传递过程中,方法jiaohuan1中的变量arr和main方法中的变量temp保存的是同一个数组
的地址,所以此时不管我们通过那个变量进行操作,都会对数组的值进行改变.
总结:址传递的最终原因是两个变量保存了同一个数组的地址,操作的是同一个数组.
案例
将上面例子中的址传递方法jiaohuan1替换成下面的方法jiaohuan3,再来观察数组temp的值,发现两个值并没有发生交换
public static void jiaohuan3(int[] arr) {//arr = temp
int[] arr2 = new int[2];
arr = arr2;
arr[0] = arr[0] ^ arr[1];
arr[1] = arr[0] ^ arr[1];
arr[0] = arr[0] ^ arr[1];
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pZVExSzD-1627046982037)(数组.assets/image-20210719194911059.png)]
原因总结:当arr = arr2执行后,arr内部保存的地址变成了3456,此时我们再通过arr进行操作的是一个新数组,与temp指向的原数组没有任何关系.所以虽然此时是址传递,但是方法内部也没有影响外部值的变化.
排序
排序,即排列顺序,将数组中的元素按照一定的大小关系进行重新排列。
根据时间复杂度和空间复杂度选择排序方法
各算法的时间复杂度
平均时间复杂度
插入排序 O(n2)
冒泡排序 O(n2)
选择排序 O(n2)
快速排序 O(n log n)
堆排序 O(n log n)
归并排序 O(n log n)
基数排序 O(n)
希尔排序 O(n1.25)
复杂度作用:了解了时间复杂度和空间复杂度,可以更好的选择算法,提高排序查找的效率.
在Java中, 我们最常用的排序有:
选择排序:固定值与其他值依次比较大小,互换位置。
冒泡排序:相邻的两个数值比较大小,互换位置。
JDK提供默认的升序排序
查询
顺序查询
顺序查询, 即遍历数组中的每一个元素, 和要查询的元素进行对比。 如果是要查询的元素,
这个下标就是要查询的下标。
查询三要素:
1.我们只找查到的第一个与key相同的元素,查询结束.
2.当查询到与key相同的元素时,返回元素的下标
3.如果没有查询到与key相同的元素,返回-1
二分查询
二分查询, 即利用数组中间的位置, 将数组分为前后两个字表。 如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。
二分查询, 要求数组必须是排序的, 否则无法使用二分查询。
可变长参数
可以接收多个类型相同的实参,个数不限,使用方式与数组相同。
在调用方法的时候, 实参的数量可以写任意多个。
作用:简化代码,简化操作等
**语法:**数据类型… 形参名
// 这里的参数paramters其实就是一个数组
static void show(int... parameters) {
//
}
二维数组
数组是一个拥有固定存储空间的连续的相同数据类型的仓库,,二维数组中,存储的是每个一维数组的地址,每一个维数组的空间不是连续的。
//应用数据类型填充的默认值是null。
二维数组, 其实就是数组中嵌套数组。
二维数组中的每一个元素都是一个小的数组。
// 这里的参数paramters其实就是一个数组
static void show(int… parameters) {
//
}
## 二维数组
数组是一个拥有固定存储空间的连续的相同数据类型的仓库,,二维数组中,存储的是每个一维数组的地址,每一个维数组的空间不是连续的。
//应用数据类型填充的默认值是null。
二维数组, 其实就是数组中嵌套数组。
二维数组中的每一个元素都是一个小的数组。
理论上来讲, 还可以有三维数组、四维数组, 但是常用的其实就是二维数组。