第三章 数组
一、数组的概述
-
数组(Array), 是多个相同类型数据按一定顺序排列的集合, 并使用一个名字命名, 并通过编号的方式对这些数据进行统一管理。
-
数组的相关概念:
-
数组名
-
下标(或索引)
-
元素
-
数组的长度
-
-
数组是引用数据类型 ,其内部元素既可以是基本数据类型,也可以是引用数据类型。
-
创建数组后会在内存中开辟一整块连续的空间,且数组的长度一旦确定,不能再修改。
-
数组的分类:
- 按照维数:一维、二维、三维……
- 按照数组元素的类型:基本数据类型元素的数组、引用数据类型元素的数组
二、一维数组的使用
-
一维数组的声明和初始化
-
声明:数组中元素数据类型+[ ]+数组名
-
初始化:
-
静态初始化:数组的初始化和数组元素的赋值操作同时进行
int[ ] ids; //声明
ids = new int[ ]{1,2,3,4}; //静态初始化,大括号前面为数组初始化,大括号里面为赋值
这里的new int[ ]可以省略,称为类型推断
-
动态初始化:数组的初始化和数组元素的赋值操作分开进行
String[ ] names = new String[5]; //声明和动态初始化,只规定了数组元素个数
-
-
-
通过索引的方式调用指定位置元素的值,索引是从0开始的,这个方法和python里一样
-
通过.length属性来获取数组的长度
-
数组的遍历:用for循环进行遍历
for(int i=0; i<array.length; i++){
//里面通过索引的方式调用相应元素
}
-
数组元素采用动态初始化时会有默认初始化值
- 数组元素是整型的:0
- 数组元素是浮点型的:0.0
- 数组元素是char型:0或’\u0000’ 注意不是’0’
- 数组元素是boolean型:false
- 数组元素是引用数据类型:null
-
数组的内存解析
内存的简化结构:
- 栈(stack)主要用来存放局部变量。
- 堆(heap)主要用来存放new出来的结构(对象,数组)
- 方法区:分为常量池和静态域,String放在常量池,static放在静态域
放在方法中的变量都叫着局部变量,左边数组名就是个变量,他定义在方法里也是局部变量,右边的new出来的,需要放在堆里,栈空间的变量存的是堆空间中数组的16位地址值,这个地址值存储在堆空间中的数组的最开始。
如果同一个变量名重新new了一个数组,则会新开辟一个地址,栈空间中的原变量会变成新的地址,原来的数组会变成垃圾,会在后期空闲时间被自动清除。
当程序执行完以后,存放在栈中的变量会依次出栈,然后堆空间的数组就会变成垃圾,随后会被清除。
三、多维数组的使用
-
可以看成是一维数组array1又作为另一个一维数组array2的元素而存在。
-
一维数组的声明和初始化
-
声明,例如:
int[][] arr; int[] arr[]; int arr[][];
-
静态初始化:
int[]][] arr1 = new int[][]{{1,2,3},{4,5},{6,8,7,9}}; int[]][] arr2 = {{1,2,3},{4,5},{6,8,7,9}}
-
动态初始化:
String[][] arr1 = new String[3][2];//表示三行两列 String[][] arr2 = new String[3][];//列可以不写,行必须写 arr2[0] = new String[2];//采用这种方式初始化,必须要在后续对外层数组的每一个元素赋值
-
-
通过索引的方式调用指定位置元素的值,索引是从0开始的,这个方法和python里一样,对于动态初始化的第二种方式,如果要调用指定元素还需要再对列进行赋值如:arr2[1] = new String[4];
-
获取数组的长度arr.length返回的是第一维的个数,如果要返回第二维的长度需要arr[1].legth
-
如何遍历二维数组:
利用循环嵌套,最外层就是第一维,然后依次类推
for (int i = 0;i < arr.length; i++){ for (int j = 0;j < arr[i].length;j++){ } }
-
数组元素的默认初始值
二维数组中外层数组如arr[1]中存放的是内层数组的地址值,内层数组的默认值和一维数组相同。
**注意:**如果采用动态初始化的第二种,外层数组的默认值为null,这个null与声明的类型无关
-
内存解析
- 栈(stack):存放变量名,变量名的值是外层数组在堆空间的首地址值
- 堆(heap):外层数组中的每一个元素存放的是内层数组在堆空间的首地址值,内层数组存 放的是具体元素值
四、数组中涉及到的常见算法
- **数组元素的赋值(杨辉三角、回形数等) **
杨辉三角:
-
第一行有 1 个元素, 第 n 行有 n 个元素
-
每一行的第一个元素和最后一个元素都是 1
-
从第三行开始, 对于非第一个元素和最后一个元素的元素。即:
yanghui[i][j] = yanghui[i-1][j-1] + yanghui[i-1][j];
回形数:
给定一个值如4,则输入四行四列,且其中的元素按顺序转圈打印,如下:
1 2 3 4
12 13 14 5
11 16 15 6
10 9 8 7
-
求数值型数组中元素的最大值、最小值、平均数、总和等
-
数组的复制、反转、查找(线性查找、二分法查找)
-
数组复制:
将一个数组赋值给另一个数组,只是将地址值赋值给了另一个数组,所以他俩都指向堆空间的同一位置,改变任意一个数组里元素,两个数组的元素值都会改变。简单的可以理解为如果有new才会在堆空间新建一个数组的空间,否则就只有原来的数组。(因此这种方式不能称为是复制)
如果需要复制,首先需要先new一个新数组,然后通过for循环的方式去对其赋值,所赋的值等于原先数组对应位置的值
-
数组反转:
public static void main(String[] args){ String[] arr = new String[]{"AA","BB","CC","DD","EE","FF"}; for (int i = 0;i < arr.length/2;i++){ String temp = arr[i]; arr[i] = arr[arr.length - 1 - i]; arr[arr.length - 1 - i] = temp; } }
-
查找
二分查找:
- 前提:所要查找的数组必须有序
- 然后跟中间元素比较,大于中间元素在右半边找(将索引的最小值改为中间值对应的索引),小于中间元素在左半边找(将索引的最大值改为中间值对应的索引,然后同理直到相等的元素或者分到只剩一个元素仍然不相等。
- 数组元素的排序算法
-
十大内部排序算法:
- 选择排序:直接选择排序、堆排序
- 交换排序:冒泡排序、快速排序
- 插入排序:直接插入排序、折半插入排序、Shell排序
- 归并排序
- 桶式排序
- 基数排序 (最后两种比较少,前八种使用较多)
-
冒泡排序法:
从头开始依次两两进行比较,如果大数在前则交换顺序,直到把最大的数放在最后,然后再从头开始两两比较,直到把次大的数放在倒数第二个位置,重复这样的操作直到排序完成。 -
快速排序法:
-
思想:
分别取两个变量一个叫low,一个叫high,low开始指向第一个元素,并将第一个元素赋给一个变量,high开始指向最后一个元素,然后l先用high所指的数与第一个数进行比较,如果比第一个数大high-1并继续比较,如果小于将high所指的值赋给low,然后low+1,开始用low所指的数进行比较,用low所指的数与第一个数进行比较,如果小于第一个数,low+1,然后继续比较,如果大于等于第一个数,将low所指的数赋给high所指的位置,然后high-1,开始用high所指的数进行比较。直到当low等于high时,low所指的位置就是第一个数在排序后的位置。
找到第一个数的位置后,数组被分成了两半,然后对这两半再分别采用上面的方法,分别找到这两半第一个元素所在位置,然后再次根据位置对半分,直到所有的都分到不能分为止,则此时排序完成。
-
方法:
采用递归的思想,首先最开始先找出第一个元素在数组中的位置,此时数组被分成了两半,对于这两半就采用递归方法,在定义函数时,需要传入原数组(因为只定义了一个数组,因此需要都在原数组上进行操作)、first(数组的第一个索引)、last(数组的最后一个索引),然后就根据上述思想进行实现。
-
五、Arrays工具类的使用
-
java.util.Arrays是数组的工具类,里面有很多数组的方法,例如常用的:
1 boolean equals(int[] a,int[] b) 判断两个数组是否相等。 2 String toString(int[] a) 输出数组信息。 3 void fill(int[] a,int val) 将数组全部用指定值填充 4 void sort(int[] a) 对数组进行排序。 5 int binarySearch(int[] a,int key) 对排序后的数组进行二分法检索指定的值。
六、数组使用中的常见异常
- 数组角标越界的异常:ArrayIndexOutOfBoundsExcetion
- 空指针异常:NullPointerException
- 数组没有赋值直接调用