在写一些算法的小程序时,最常使用的就是数组了。
数组的效率
数组的大小是固定的。数组可以分为无序数组和有序数组。
无序数组的插入很简单,就是在最后加入一个数据项,因此效率是常数O(1)。但是无序数组的查找很慢,需要遍历整个数组,因此效率是O(n).
有序数组的插入很慢,需要先查找再插入。
-------------------------------------------------------
无序数组的查找--线性查找 O(n)
有序数组的查找--二分查找 O(log n)
无序数组的插入 O(1)
有序数组的插入 O(n)
无序数组的删除 O(n)
有序数组的删除 O(n) 尽管查找是log n但是需要将后面的数据项都前移,所以还是n
--------------------------------------------------------
因此我们可以得到以下结论:
1,无序数组的查找效率低下,有序数组则很高。
2,无序数组的插入很高效,有序数组则很低。
3,两种数组删除的效率都比较低。
因此我们经常会根据实际情况,使用其他数据结构来代替数组。
数组的声明和初始化
很简单:
int[] array = {1,2,3};
int[] arrayB = new int[4]; \\这里数组中的元素全部初始化为0
除了可以在数组中放置primitive type外,也可以存放任意类:
Dog[] dogArray = new Dog[2];
此时数组中的项都被初始化为null,赋值以后,则存放了Dog的实例的reference。
在泛型出现之前,其它的container都不能检查其中存放的对象的类型,它们将存放的对象全部看做Object。
而array就比较特别,int[]就已经实现了编译时检查是否是int了。
当然了,有泛型后,其他的container也都可以了。
array其实对应的类是java.util.Arrays类。凡是int[]这样声明的对象,都是array。但是不能这样定义一个数组:
Arrays[] arrayC = new Arrays[5];
编译是没有问题的,但是里面的元素就必须是array对象了。同时查看java对于这个类的API可以发现,这个类的说明中没有构造函数,并且所有的方法都是静态方法。
Arrays的静态方法
声明了一个数组之后,会发现array.toString() 等方法都是Object的。例如:
int[] arrayA = {1,2,3};
System.out.println(arrayA.toString());
打印出来的是“[I@2f9ee1ac”。因为这个toString是Object的,它转换出来的是对象的id。而我们的本意是想打印出[1,2,3]。
因此很多人觉得使用array很不方便。其实此时就应该使用Arrays的静态方法。
1,打印数组
System.out.println(Arrays.toString(arrayA));
2,快速填充数组
public static void main(String[] args) {
int[] a = new int[100]; \\其实这里所有元素已经全部被初始化为0
Arrays.fill(a, 1);
System.out.print(Arrays.toString(a));
}
3,还有一个经常使用的Arrays.equals(),用于判断两个数组是否相等。Arrays.sort()等等。其他方法大家自己看吧。
4,将array转换为List
Integer[] coins = {1,2,3}; //这里如果是int[]的话,无法生成list。因为list中只能存对象。
List l = Arrays.asList(coins);
System.out.println(l.size());
ArrayList
The array is Java’s most efficient way to store and randomly access a sequence of object references.
Array的长度在初始化的时候就已经定了,不可更改。所以我们更常使用的是ArrayList。然而灵活是需要成本的(overhead),因此ArrayList的性能明显比Array差。
我们可以这样声明并初始化一个ArrayList:
ArrayList al = new ArrayList();
或使用泛型:
ArrayList<student> al = new ArrayList<student>();
还可以方便的将ArrayList转换成Array:
al.toArray();