数组
一维数组
什么是数组?
数组是具有相同数据类型且按一定次序排序的一组变量的集合体。即用一个变量名表示一批数据。Java为数组在内存中分配一段连续的空间,这段空间中存储数据的个数是固定的,数组就是一个容器,用来存一批同种类型的数据的。
- 数组元素:构成数组的每一个元素
- 数组下标:下标就是数组元素在数组中的位置。下标从0开始,依次累加1,也称为索引。
- 数组大小:数组中元素的个数,也称为数组的长度。
结论:遇到批量数据的存储和操作时,数组比变量更适合
数组的定义和访问
Java中定义数组有两种语法格式: 数据类型 数组名[ ]; 或 数据类型[ ] 数组名;
例如: String names[] 或 String[] names 推荐第二种方式
语法解析:
- 数组是什么数据类型,数组的元素就是什么数据类型
- 数组的特征是[ ]
- 数组是引用类型
数组有两种初始化的方式,一种是静态初始化、一种是动态初始化。我们先用静态初始化来学习数组的操作
静态初始化数组
定义数组、为数组元素分配内存、数组元素初始化,这三步可以合并在一起写,例如:
int[] scores = new int[]{12,56,34,78};
或
int[] scores = {12,56,34,78};
在定义数组时直接给数组中的数据赋值这种方式称为静态初始化。标准格式是
数据类型[] 变量名 = new 数据类型[]{元素1,元素2,元素3};
简化为:
数据类型[] 变量名 = {元素1,元素2,元素3};
String[] names = {"金文涛", "李瑶瑶", "小樊同学"...};
System.out.println(names[1]);
数组在计算机中的基本原理
我们知道数组是怎么定义的之后,那么接下来看一下数组在计算机中的基本原理。我们以 int[] ages = {12,24,36}; 这句话为例,看一下这句话到底在计算机中做了那些事情。
- 首先,左边 int[] ages 表示定义了一个数组类型的变量,变量名叫ages
- 其次,右边 {12,24,36} 表示创建一个数组对象,你完全可以把它理解成一个能装数据的东西。这个对象在内存中会有一个地址值 [I@4c873330 ,每次创建一个数组对象都会有不用的地址值。
- 然后,把右边的地址值 [I@4c873330 赋值给左边的ages变量
- 所以,ages变量就可以通过地址值,找到数组这个东西。
数组的动态初始化
刚才我们初始化数组时,都是直接将元素写出来。但是还有另一个初始化数组的方式叫 动态初始化。
动态初始化不需要我们写出具体的元素,而是指定元素类型和长度就行。格式如下
数据类型[] 数组名;
数组名 = new 数据类型[数组长度];
例如: names = new String[5];
定义数组和为数组元素分配内存,这两步可以合并在一起写,例如:
String[] names = new String[5];
// 数据类型[] 数组名 = new 数据类型[长度];
int[] arr = new int[3];
下面是动态初始化数组的原理图。我们发现 int[] arr 其实就是一个变量,它记录了数组对象的地址值,而且数组中的元素默认值是0。
注意:
使用动态初始化定义数组时,根据元素类型不同,默认值也有所不同。
默认初始值
使用数组实现斐波拉切数列
public static void main(String[] args) {
// 输入 n 输出前 n 个数 存储到数组 再输出
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个数字");
int number = sc.nextInt();
int[] feibo = new int[number];
// int prev = 1; // 第一个值
// int next = 1; // 第二个值
// feibo[0] = prev;
// feibo[1] = next;
if (number == 1) {
feibo[0] = 1;
} else if (number == 2) {
feibo[0] = 1;
feibo[1] = 1;
} else {
// feibo : 1 1 2 3
feibo[0] = 1;
feibo[1] = 1; // 1 1 x
for (int i = 3; i <= number; i++) { // i = 3 i = 4
feibo[i - 1] = feibo[i - 3] + feibo[i - 2];
// int curr = prev + next;
// feibo[i - 1] = curr;
// prev = next;
// next = curr;
}
}
for (int i = 0; i < feibo.length; i++) {
System.out.println(feibo[i]);
}
}
排序
冒泡排序
冒泡排序(Bubble Sort) 最为简单的一种排序,通过重复走完数组的所有元素,通过打擂台的方式两个两个比较,直到没有数可以交换的时候结束这个数,再到下个数,直到整个数组排好顺序。因一个个浮出所以叫冒泡排序。双重循环时间 O(n^2)
算法描述:
- 比较相邻两个数据如果。第一个比第二个大,就交换两个数
- 对每一个相邻的数做同样1的工作,这样从开始一队到结尾一队在最后的数就是最大的数。
- 针对所有元素上面的操作,除了最后一个。
- 重复1~3步骤,知道顺序完成。
public class Text1 {
public static void main(String[] args) {
//冒泡排序
int[] arr={3,6,1,6,9,29,83,26,74,91};
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1; j++) {
if (arr[j] > arr[j + 1]){
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
System.out.println(Arrays.toString(arr));//Arrays.toString方便地输出数组。 这个方法是是用来将数组转换成String类型输出的,入参可以是long,float,double,int,boolean,byte,object型的数组。
}
}
选择排序
选择排序(Select Sort) 是直观的排序,通过确定一个 Key 最大或最小值,再从带排序的的数中找出最大或最小的交换到对应位置。再选择次之。双重循环时间复杂度为 O(n^2)
算法描述:
- 在一个长度为 N 的无序数组中,第一次遍历 n-1 个数找到最小的和第一个数交换。
- 第二次从下一个数开始遍历 n-2 个数,找到最小的数和第二个数交换。
- 重复以上操作直到第 n-1 次遍历最小的数和第 n-1 个数交换,排序完成。
public class Text2 {
public static void main(String[] args) {
//选择排序
int[] arr={23,54,16,48,81,26,99,8,59,2};
for (int i = 0; i < arr.length - 1; i++) {
int min = i;//定义下标为0的数为最小值
for (int j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[min]){
min = j;
}
}
int temp = arr[min];
arr[min] = arr[i];
arr[i] = temp;
}
System.out.println(Arrays.toString(arr));
}
}
插入排序
插入排序的原理是从数组第一个元素开始形成一个元素序列,从第二个元素开始比较与第一个元素的大小然后形成序列,以此类推直到最后一个元素。
对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入
public class Text3 {
public static void main(String[] args) {
//插入排序
int[] arr={23,56,21,95,79,12};
for (int i = 1; i < arr.length; i++){
int index = arr[i];//当前值
int next = i - 1;//前一个值的坐标
while (next >= 0 && arr[next] > index){
arr[next + 1] = arr[next];//后移一位
next--;
}
arr[next + 1] = index; // 当前值的位置
}
System.out.println(Arrays.toString(arr));
}
}
二分查找
二分查找(Binary Search)算法,也叫折半查找算法。二分查找的思想非常简单,有点类似分治的思想。二分查找针对的是一个有序的数据集合,每次都通过跟区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为 0。
public class Text4 {
public static void main(String[] args) {
//二分查找
int [] arr = {1,3,5,6,7,9,10};
int n = 9;
int left = 0;
int right = arr.length - 1;
int index = -1;
while (left <= right) {
int middle = (right + left) >> 1;
if (arr[middle] == n){
index = middle;
break;
} else if (arr[middle] > n) {
right = middle - 1;
}else {
left =middle + 1;
}
}
System.out.println(index);
}
}
多维数组
在 Java 中,可以使用多维数组来存储多个数据值,以便更好地组织和访问这些数据。Java 中的多维数组是一种数组的数组,即一个数组的元素也是一个数组。Java 中的多维数组可以包含任意数量的维度。在处理多维数组时,需要注意数组下标的范围,以避免数组越界异常。同时,还可以使用循环嵌套来遍历多维数组中的所有元素。
二维数组
Java中定义和操作多维数组的语法与一维数组类似。在实际应用中,三维及其以上的数组使用很少,主要使用二维数组。使用二维数组同一维数组的步骤,(1)定义数组、(2)为数组元素分配内存、(3)数组元素初始化、(4)使用数组。下面主要以二维数组为例进行讲解。
定义二维数组
数据类型[][] 数组名;
or
数据类型 数组名[][];
语法解析:
[][] 表示二维数组,前面的[ ]表示第一维,后面的[ ]表示第二维。
[][] 放在数组名的前面或后面都是正确的。
前[]可以限制二维数组的长度。
int[][] arr = new int[][]{};
报错
// 二维数组初始化
int[][] arr = new int[3][4]; // 动态初始化
arr[0][0] = 1;
int[][] arr1 = new int[][]{ // 静态初始化
{1, 2, 3},
{2, 3},
{3, 4, 5, 4}
};
[][] 表示二维数组,前面的[ ]表示第一维,后面的[ ]表示第二维。
[][] 放在数组名的前面或后面都是正确的。
> 前[]可以限制二维数组的长度。
>
> `int[][] arr = new int[][]{};` 报错
```java
// 二维数组初始化
int[][] arr = new int[3][4]; // 动态初始化
arr[0][0] = 1;
int[][] arr1 = new int[][]{ // 静态初始化
{1, 2, 3},
{2, 3},
{3, 4, 5, 4}
};