数组详解
什么是数组
- 数组是相同类型数据的有序集合
- 数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成
- 其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们
数组的声明和创建
- 首先必须**声明*8数组变量,才能在程序中使用数组,下面是声明数组变量的语法:
dataType[] arrayRefVar;//首选的方法
dataType arrayRefVar[];//效果相同,但不是首选方法(C&C++风格)
- Java语言使用new操作符来创建数组(开辟存储空间),语法如下:
dataType[] arrayRefVar = new dataType[arraySize];
-
数组的元素是通过索引访问的,数组索引从0开始
-
获取数组的长度
int[] array=new int[10];//创建一个长度为10的int型数组array
array[0]=1;//数组array的第一个元素赋值为1
array[9]=10;//数组array的第十个元素赋值为10
int length=array.length;//10
三种初始化及内存分析
Java内存分析
- 堆
- 存放new的对象和数组
- 可以被所有的线程共享,不会存放别的对象引用
- 栈
- 存放基本变量类型(会包含这个基本类型的具体数值)
- 引用对象的变量(会存放这个引用在堆里面的具体地址)
- 方法区
- 可以被所有的线程共享
- 包含了所有的class和static变量
三种初始化
- 静态初始化
int[] array1= {1,2,3};
- 动态初始化
int[] array2=new int[10];
array2[0]=1;//后期赋值
- 数组的默认初始化
- 数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化(0或0.0或null)
下标越界及小结
- 数组的四个基本特点
- 其长度是固定的,数组一旦被创建,它的大小就是不可以被改变的
- 其元素必须是相同类型,不允许出现混合类型
- 数组中的元素可以是任何数据类型,包括基本类型和引用类型
- 数组变量属于引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量
- 数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中的
- 数组边界
- 下标的合法区间[0,length-1],如果越界就会报错
- ArrayIndexOutOfBoundsException:数组下标越界异常
- 小结:
- 数组是相同数据类型(数据类型可以为任意类型)的有序集合
- 数组也是对象。数组元素相当于对象的成员变量
- 数组长度是确定的,不可变的。如果越界,则报ArrayIndexOutOfBounds
数组的使用
普通的For循环
public class Demo01 {
public static void main(String[] args) {
int[] array= {1,2,3,4,5};
//遍历输出数组元素
for (int i = 0; i < array.length; i++) {
System.out.print(array[i]+" ");
}
System.out.println();
System.out.println("==================");
//计算所有元素的和
int sum=0;
for (int i = 0; i < array.length; i++) {
sum+=array[i];
}
System.out.println("sum="+sum);
System.out.println("==================");
//查找最大元素
int max=array[0];
for (int i = 1; i < array.length; i++) {
if(max<array[i])max=array[i];
}
System.out.print("max="+max);
}
}
/*输出结果
1 2 3 4 5
==================
sum=15
==================
max=5
*/
For-Each循环
public class Demo01 {
public static void main(String[] args) {
int[] array= {1,2,3,4,5};
for (int i : array) {//无法获取下标,适合遍历输出
System.out.print(i+" ");
}
}
}
/*输出结果
1 2 3 4 5
*/
数组作为方法的参数
public class Demo01 {
public static void main(String[] args) {
int[] array= {1,2,3,4,5};
System.out.print("sum="+sum(array));//调用sum方法
}
public static int sum(int[] array){
int sum=0;
for (int i = 0; i < array.length; i++) {
sum+=array[i];
}
return sum;
}
}
/*输出结果
sum=15
*/
数组作为方法的返回值
public class Demo01 {
public static void main(String[] args) {
int[] array= {1,2,3,4,5};
print(reverse(array));//输出翻转后的array
}
public static int[] reverse(int[] array){//翻转array,返回reverse数组
int[] reverse=new int[array.length];
for (int i = 0; i < array.length; i++) {
reverse[i]=array[array.length-i-1];
}
return reverse;
}
public static void print(int[] array){//遍历输出array
for (int i = 0; i < array.length; i++) {
System.out.print(array[i]+" ");
}
}
}
/*输出结果
5 4 3 2 1
*/
二维数组
- 多维数组可以看成是数组的数组, 比如二维数组就是一个特殊的一维数组,它的每一个元素都是一个一维数组
- 二维数组
int[][] a1=new int[2][5];
int a2[][]=new int[2][5];
- 解析:以上二维数组可以看成是一个两行五列的数组
- 多维数组的遍历
public class Demo01 {
public static void main(String[] args) {
int[][] array={{1,3,5,7,9},{0,2,4,6,8}};
print(array);
}
public static void print(int[][] array){
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {//遍历一维数组array[i]
System.out.print(array[i][j]+" ");
}
System.out.println();//遍历输出一维数组array[i]后换行
}
}
}
/*输出结果
1 3 5 7 9
0 2 4 6 8
*/
Arrays类讲解
- 数组的工具类java.util.Arrays
- 由于数组对象本身并没有什么方法可以供我们调用,但API中提供了一个工具类Arrays供我们使用,从而可以对数据对象进行一些基本的操作
- 查看JDK帮助文档
- Arrays类中的方法都是static修饰的静态方法,在使用的时候可以直接使用类名进行调用,而无需使用对象来调用
- 常用功能:
- 给数组赋值:fill
- 对数组排序:sort(升序)
- 比较数组是否相等:equals
- 查找数组元素:binarySearch(二分查找)
public class Demo01 {
public static void main(String[] args) {
int[] array={54,34,3,23,234,5,57,86};
//输出array对象的HashCode
System.out.println("输出array对象的HashCode:");
System.out.println(array);
//输出array
System.out.println("输出array:");
System.out.println(Arrays.toString(array));
//升序排序array
System.out.println("升序排序array:");
Arrays.sort(array);
System.out.println(Arrays.toString(array));
//给array数组全部赋值为0
System.out.println("给array数组全部赋值为0:");
Arrays.fill(array,0);
System.out.println(Arrays.toString(array));
//给array数组下标为2~6的元素赋值为1
System.out.println("给array数组下标为2~6的元素赋值为1:");
Arrays.fill(array,2,7,1);//下标范围[2,7)
System.out.println(Arrays.toString(array));
}
}
/*输出结果
输出array对象的HashCode:
[I@1b6d3586
输出array:
[54, 34, 3, 23, 234, 5, 57, 86]
升序排序array:
[3, 5, 23, 34, 54, 57, 86, 234]
给array数组全部赋值为0:
[0, 0, 0, 0, 0, 0, 0, 0]
给array数组下标为2~6的元素赋值为1:
[0, 0, 1, 1, 1, 1, 1, 0]
*/
冒泡排序(升序)
- 遍历数组,比较数组中两个相邻的元素,如果前一个数比后一个数大,就交换它们的位置
- 经过一轮遍历会将最大的数交换到数组的最后
- 从头开始遍历,但不会比较到最后一个数……经过一轮遍历会将第二大的数交换到数组的最后
- 从头开始遍历,但不会比较到最后两个数……经过一轮遍历会将第三大的数交换到数组的最后
- 依次循环直到结束……
public class Demo01 {
public static void main(String[] args) {
int[] array={54,34,3,23,234,5,57,86};
sort(array);
System.out.println(Arrays.toString(array));
}
//冒泡排序
public static void sort(int[] array) {
int t;
for (int i = 0; i < array.length-1; i++) {
for (int j = 0; j < array.length-1-i; j++) {
if(array[j]>array[j+1]){
t=array[j];
array[j]=array[j+1];
array[j+1]=t;
}
}
}
}
}
/*输出结果
[3, 5, 23, 34, 54, 57, 86, 234]
*/
稀疏数组(SparseArray)
- 当一个数组中大部分元素为0,或者为同一值时,可以使用稀疏数组来保存该数组
- 稀疏数组的处理方式:
- 记录数组一共有几行几列,有多少个不同数值
- 把具有不同数值的元素的行、列、数值记录在一个小规模的数组中,从而缩小程序的规模
- 稀疏数组格式:
SparseArray | 第0列 | 第1列 | 第2列 |
---|---|---|---|
第0行 | 总行数 | 总列数 | 默认值 |
第1行 | 行数1 | 列数1 | 数值1 |
第2行 | 行数2 | 列数2 | 数值2 |
第3行 | 行数3 | 列数3 | 数值3 |
…… | …… | …… | …… |
- 案例:将一个11X11的二维数组转换成稀疏数组,并将稀疏数组以原数组的形式输出
public class Demo01 {
public static void main(String[] args) {
int[][] array1=new int[11][11];
array1[3][4]=1;
array1[5][6]=1;
print(array1);
System.out.println("===================");
int[][] array2=sparse(array1,0);
print(array2);
System.out.println("===================");
printSparse(array2);
}
//转换成稀疏数组
public static int[][] sparse(int[][] array,int x){//接收原数组以及默认值
int n=0;
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
if(array[i][j]!=x){
n++;//记录不同值的个数,以确定新建的稀疏数组的行数
}
}
}
int[][] sparse=new int[n+1][3];
sparse[0][0]=array.length;
sparse[0][1]=array[0].length;
sparse[0][2]=x;//第一行存储数组基本信息
int k=1;
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
if(array[i][j]!=x){
sparse[k][0]=i;
sparse[k][1]=j;
sparse[k][2]=array[i][j];
k++;//将不同值的行标、列标和数值逐个存储至稀疏数组
}
}
}
return sparse;//返回生成的稀疏数组
}
//输出数组
public static void print(int[][] array){
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
System.out.print(array[i][j]+" ");
}
System.out.println();
}
}
//将稀疏数组还原输出
public static void printSparse(int[][] array){
int k=1;
for (int i = 0; i < array[0][0]; i++) {
for (int j = 0; j < array[0][1]; j++) {
if(k<array.length&&i==array[k][0]&&j==array[k][1]){//利用逻辑运算符的短路特性,当k>=array.length时不执行后续判断,避免了下标越界问题
System.out.print(array[k][2]+" ");
k++;//稀疏数组存放不同值的顺序与遍历顺序相同,因此可逐个定位并输出
}else {
System.out.print(array[0][2]+" ");//否则输出默认值
}
}
System.out.println();
}
}
}
/*输出结果
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
===================
11 11 0
3 4 1
5 6 1
===================
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
*/