1 数组概述
数组是相同类型
数据的有序
集合。
数组描述的是相同类型的若干个数据,按照一定的先后次序组合而成。
其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标
来访问它们。
数组的四个基本特点
- 数组长度是确定的。数组一旦被创建,它的大小就是不可以改变的。
- 数组的元素必须是相同数据类型,不允许出现混合类型。
- 数组中的元素可以是任何数据类型,包括
基本类型
和引用类型
。 - 数组变量属于引用类型,也可以将数组看成是对象,数组中的每个元素相当于该对象的成员变量。数组本身就是对象,Java中对象存储在堆中,因此数组无论保存的是原始类型还是其他对象类型,数组对象本身是在堆中的。
2 数组的声明与创建
首先必须声明数组变量,才能在程序中使用数组。
下面是声明数组变量的语法:
dataType[] arrayRefVar; // java首选声明方法
dataType arrayRefVar[]; // C/C++风格声明方法
Java语言使用new操作符来创建数组,语法如下:
dataType[] arrayRefVar = new dataType[arraySize];
数组的元素是通过索引访问的,数组索引从0开始。
获取数组长度:
arrays.length
3 内存分析
Java内存
堆
- 存放new的对象和数组
- 可以被所有的线程共享,不会存放别的对象引用
栈
- 存放基本变量类型(会包含这个基本类型的具体数值)
- 引用对象的变量(会存放这个引用在堆里面的具体地址)
方法区
- 可以被所有的线程共享
- 都包含了所有的class和static变量
4 三种初始化
首先定义类Human,参数为性别
和年龄
,均为整数类型。
public class Human {
int gender;
int age;
//含参构造器
public Human(int genderKey, int ageKey) {
gender = genderKey;
age = ageKey;
}
}
静态初始化
int[] intArray = {1, 2, 3};
Human[] humans = {new Human(0, 18), new Human(1, 20)};
动态初始化
int[] array = new int[3];
array[0] = 1;
array[1] = 2;
array[2] = 3;
数组的默认初始化
数组是引用类型,它的元素相当于类的实例变量,因此数组一经空间分配,其中的每个元素也会被按照实例变量同样的方式被隐式初始化。
整形数组中未被定义的元素默认值为0。
5 数组边界
下标的合法区间:[0, length - 1]
如果越界就会报错:
int[] array = new int[3];
System.out.println(array[3]);
运行之,
java.lang.ArrayIndexOutOfBoundsException 数组下标越界异常
小结:
- 数组是相同数据类型(数据类型可以为任意类型)的有序集合。
- 数组是对象,数组元素相当于对象的成员变量。
- 数组长度是确定的,不可变的。如果下标越界则报:ArrayIndexOutOfBounds
6 数组的使用
四种简单的使用方法:
- 普通for循环
- for-each循环
- 数组作方法参数
- 数组作方法返回值
反转数组
反转数组方法:
public static int[] reverse(int[] originalArray) {
int[] reversedArray = new int[originalArray.length];
for (int i = 0; i < originalArray.length; i ++) {
reversedArray[originalArray.length - i - 1] = originalArray[i];
}
return reversedArray;
}
输出数组元素:
public static void print(int[] array) {
for (int i : array) {
System.out.print(i + "\t");
}
System.out.println();
}
测试之:
7 多维数组
多维数组可以看成是数组的数组,比如二维数组就是一个特殊的一维数组,其中每个元素都是一个一维数组。
二维数组定义举例:
int array[][] = new int[2][3];
8 Arrays类详解
数组工具类:java.util.Arrays
虽然数组对象本身没啥方法可以供我们调用,但API中提供了一个工具类Arrays供我们使用,从而可以对数据对象进行一些基本的操作。
可以通过查看JDK帮助文档来了解Arrays类相关方法。
Arrays类中的方法都是static修饰的静态方法,在使用时可以直接使用类名进行调用,不用使用对象来调用。
常用功能:
- fill方法赋值
- sort方法升序排序
- equals方法比较元素是否相等
- binarySearch方法二分查找数组元素
int[] array1 = {0, 10, 100, 22, 33};
System.out.println(Arrays.toString(array1) + "\n");
// 升序排序
Arrays.sort(array1);
System.out.println(Arrays.toString(array1) + "\n");
// 二分查找
System.out.println(Arrays.binarySearch(array1, 50));
System.out.println(Arrays.binarySearch(array1, 33));
System.out.println(Arrays.binarySearch(array1, 1, 4, 22) + "\n");
// 自动填充
Arrays.fill(array1, 1, 4, 999 );
System.out.println(Arrays.toString(array1) + "\n");
// 元素比较
int[] array2 = {1, 999, 999, 999, 1}; // array1 : 0, 999, 999, 999, 100
System.out.println(Arrays.equals(array1, array2));
System.out.println(Arrays.equals(array1, 1, 4, array2, 1, 4) + "\n");
输出为:
[0, 10, 100, 22, 33]
[0, 10, 22, 33, 100]
-5
3
2
[0, 999, 999, 999, 100]
false
true
在二分查找方法中,参数数组中的元素必须为升序排列的元素,查找成功返回元素下标
,不成功则返回插入位置下标加一的相反数
。
9 冒泡排序
最出名的排序算法之一,共有八大排序。
冒牌排序的代码相对较简单,两层循环,外循环冒泡轮数,内循环依次比较,时间复杂度为$ O(n^{2}) $。
public static void bubbleSort(int[] array){
for(int i = 0; i < array.length - 1; i ++) {
boolean flag = true; // 假设排序已完成
for(int j = 0; j < array.length - i - 1; j ++) {
if(array[j] > array[j + 1]) {
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
flag = false; // 发生对换,证明排序未完成
}
}
if (flag) {
break; // 结束排序,优化算法
}
}
}
10 稀疏数组
需求:编写五子棋游戏中,有存盘退出和续上盘的功能。
问题:因为该二维数组中很多值是默认值0,因此记录了很多无意义的数据。
解决:稀疏数组。
当一个数组中大部分元素为0或同一值时,较浪费内存,可以使用稀疏数组来保存该数组。
稀疏数组的处理方式是:
- 记录数组一共有几行几列,多少个不同值
- 具有不同值的元素和行列记录在一个小规模数组中,从而缩小数组规模
原始数组:
$$ \begin{pmatrix} 0&0&0&22&0&0&15 \\ 0&11&0&0&0&17&0 \\ 0&0&0&-6&0&0&0 \\ 0&0&0&0&0&39&0 \\ 91&0&0&0&0&0&0 \\ 0&0&28&0&0&0&0 \end{pmatrix} $$
稀疏数组:
index | row | column | value |
---|---|---|---|
0 | 6 | 7 | 8 |
1 | 0 | 3 | 22 |
2 | 0 | 6 | 15 |
3 | 1 | 1 | 11 |
4 | 1 | 5 | 17 |
5 | 2 | 3 | -6 |
6 | 3 | 5 | 39 |
7 | 4 | 0 | 91 |
8 | 5 | 2 | 28 |
代码实现原始数组与稀疏数组互相转换:
// 将原始数组转换为稀疏数组
public static int[][] convertToSparse(int[][] original) {
// 1.获取有效值个数
int sum = 0;
for(int[] row : original) { // 行
for (int column : row) { // 列
if (column != 0) { // 判断是否为有效值
sum++;
}
}
}
// 2.创建稀疏数组
int[][] sparse = new int[sum + 1][3];
sparse[0][0] = original.length;
sparse[0][1] = original[0].length;
sparse[0][2] = sum;
// 3.存储数据
int count = 1;
for(int i = 0; i < original.length; i ++) {
for(int j = 0; j < original[i].length; j ++) {
if(original[i][j] != 0) {
sparse[count][0] = i;
sparse[count][1] = j;
sparse[count][2] = original[i][j];
count ++;
}
}
}
return sparse;
}
// 将稀疏数组转换为原始数组
public static int[][] convertToOriginal(int[][] sparse) {
// 1.创建原始数组
int[][] original = new int[sparse[0][0]][sparse[0][1]];
// 2.存储数据
for(int i = 1; i <= sparse[0][2]; i ++) {
original[sparse[i][0]][sparse[i][1]] = sparse[i][2];
}
return original;
}
测试之,
感谢 狂神说 提供的java学习资源。