1.数组的定义、声明和创建
定义:数组是相同类型数据的有序集合,其中每一个数据称为数组元素,我们通过数组的下标(即序号)去访问每个元素。注意:在Java中,数组元素下标是从0开始的。
声明:有两种方法。
1)datatype[] arrayRefVar; //首选方法;
2)datatype arrayRefVar[]; //和上一个方法效果相同,但这里是c++、c语言的代码习惯。
创建:在声明后需要用new操作符来创建一个数组。
datatype[] arrayRefVar = new dataType[arraySize];
创建之后再对数组元素进行初始化,如果没有初始化那么元素就均为默认值(比如int类型为0,string类型为null等)。
数组长度获取:arrays.length
2.数组的初始化和内存分析
Java内存一般分为三个部分:
1)堆:主要用于存放new的对象和数组,可以被所有的线程共享,不会存放别的对象引用;
2)栈:存放基本变量类型(包括这个基本类型的具体数值),也存放引用对象的变量(会存放这个引用在堆里面的具体地址);
3)方法区:包含了所有的class和static变量,可以被所有的线程共享。
在声明并创建数组的整个过程里,Java的内存分配:
数组的三种初始化类型
1)静态初始化;
int[] a = {1, 2, 3, 4, 5}; //直接创建数组并赋值
Man[] mans = {new Man(), new Man2()}; //引用类型数组
2)动态初始化;
int[] nums; //声明一个数组
nums = new int[5]; //创建一个数组
nums[0] = 1; //给数组赋值
或者也可以 int[] nums = new int[5]; //直接声明并创建数组
3)默认初始化。
数组是引用类型,其元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也如实例变量一般被隐式初始化(0/0.0/null)。一般动态初始化就伴有默认初始化的过程。
数组的特点:
1)Java中数组长度为定值,数组一旦被创建,数组长度就不能改变;
2)数组元素类型可以是任何数据类型,包括基本数据类型或者引用类型,但必须是相同类型,不能出现混合类型;
3)数组变量属于引用类型,数组可以看成为对象,其中每个元素可以看做对象的成员变量。数组本身是作为对象保存在JVM的堆中,因此数组不论是保存原始类型还是引用类型,其本身是在堆中的。
数组下标越界:数组的下标范围为[0, array.length-1],当输入的数组下标超出了数组长度,此时内存读取越界,java会报报java.lang.ArrayIndexOutOfBoundsException错误。
多维数组:可以看做是数组的数组,例如int[][] arrays = {{1, 2}, {1, 3}, {1, 4}, {1, 5}, {1, 6}}; //这里数组可以看做是5行2列的矩阵,[5][2]
3.Arrays类
Java中的工具类:java.util.Arrays,主要是用于对数组中的数据对象进行一些基本操作,具体方法参考https://docs.oracle.com/javase/8/docs/api/的API帮助文档。这个工具类中的所有方法都是static类型的,所以我们是直接使用类名进行调用,而不能使用对象来进行调用。下面是一些常用的功能:
1)fill方法:将数组中部分或全部元素替换成你提供的某个值,Arrays.fill(int[] a, int value) 或 Arrays.fill(int[] a, int fromIndex i, int toIndex J, int value) //第二个为部分替换;
2)sort方法:将数组中元素按升序排列;
3)equals方法:比较数组中元素是否相等;
4)binarySearch方法:对排列好的数组进行二分查找法操作。
我们不需要过分依赖Java中已有的工具类,根据要实现的功能特点,很多时候我们也可以自己编写相关算法以更好地实现我们的目的,工具类主要为了避免重复造轮子的低效场景。
4.冒泡排序
冒泡排序是笔试或面试中常考的排序算法之一(常见的排序算法有8种)。
基本思路:两层循环,外层为冒泡轮数(一般循环次数为数组长度-1),内层依次对数组中相邻的两个数进行比较,如果第一个数大于第二个,则将二者换位(升序冒泡),内层的循环次数一般为数组长度-1-外层当前冒泡轮数。具体细节见下图示例代码。
整体的时间复杂度为O(n^2)。
算法示例:
代码示例:
结果:
5.稀疏数组
稀疏数组是一种数据结构,主要用于数组(矩阵)压缩。当一个数组大部分元素为同一值(比如0)时,此时包含较多的无效值,我们可以通过稀疏数组来保存这个数组,这样保存只需要较小的存储空间,从而实现了压缩的效果。
具体算法原理:
1)记录数组的行列数,以及其中的有效数数量;
2)记录有效值及其行列坐标;
3)将上述数据保存在列数为3的稀疏矩阵中,第一行分别存储行列数及有效数数量,之后的每一行分别存储有效值的行列坐标及对应数值。
示例:
原数组:
稀疏数组:
算法代码示例:
结果: