List集合的重要性不言而喻,直接開幹。(下面測試基於openjdk1.8)
ArrayList: 底層採用的是數組,所以增刪慢,查找快。
增刪慢 : 比如你的數組裏面現在有5個元素(對應下標是0-4),你現在需要往下標爲2的地方添加元素,那麼數組中下標爲2,3,4的元素就需要往後移,但是如果你只是添加到數組末尾,是不用移動的(導致集合擴容除外);刪除也一樣,刪除中間的就會導致後面的元素往前移。
查找快 :可以通過數組下標直接定位到元素(時間複雜度爲O(1)).
遍歷 :for循環遍歷和iterator遍歷時間複雜度都爲O(n),但還是有區別的,如下:
for (int i = 0; i < list.size(); i+=3) {//n 表示你要找幾個元素
list.get(i);
}
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {//n 表示list的長度
iterator.next();
}
LinkedList:底層採用的是鏈表,所以增刪快
增刪快:增刪只需要移動鏈表的節點指針,查找慢
查找慢:從鏈表頭開始挨着一個一個比對(時間複雜度爲O(n)).
遍歷:for循環遍歷,時間複雜度爲O(n^2);iterator遍歷時間複雜度爲O(n),如下:
for (int i = 0; i < list.size(); i+=3) {
list.get(i);//每一次get,都需要遍歷一次鏈表
}
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {//只會遍歷一次鏈表
iterator.next();//每調用一次next,只是將遍歷的指針往後面移一次
}
ArrayList查找快 增刪慢,LinkedList查找慢增刪快.
下面大家思考這樣一個問題:往集合插入10000個元素,然後再遍歷出來,那個List更快?如果將數量增加到100000,又是那個List更快?
直接用代碼證明:
public class TestList {
public static void main(String[] args) {
testArrayList(10000);
System.out.println("=============================");
testLinkedList(10000);
}
public static void testArrayList(int num) {
long start = System.nanoTime();
List<Integer> list = new ArrayList<Integer>();
List<Integer> list2 = new ArrayList<Integer>();
for (int i = 0; i < num; i++) {
list.add(i);
}
long addEndTime = System.nanoTime();
System.out.println("ArrayList insert spend time:" + (addEndTime - start) / 100);
for (int i = 0; i < num; i++) {
//每次都從中間添加新元素,這樣後半部分的元素就需要往後移動
//add(int index, Integer element)
list2.add(i/2, i);
}
long addEndToTime = System.nanoTime();
System.out.println("ArrayList insertTo spend time:" + (addEndToTime - addEndTime) / 100);
for (int i = 0; i < list.size(); i++) {
list.get(i);
}
long forEndTime = System.nanoTime();
System.out.println("ArrayList foreach spend time:" + (forEndTime - addEndTime) / 100);
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
iterator.next();
}
long end = System.nanoTime();
System.out.println("ArrayList iterator spend time:" + (end - forEndTime) / 100);
}
public static void testLinkedList(int num) {
long start = System.nanoTime();
List<Integer> list = new LinkedList<Integer>();
for (int i = 0; i < num; i++) {
list.add(i);
}
long addEndTime = System.nanoTime();
System.out.println("LinkedList insert spend time:" + (addEndTime - start) / 100);
for (int i = 0; i < list.size(); i++) {
list.get(i);
}
long forEndTime = System.nanoTime();
System.out.println("LinkedList foreach spend time:" + (forEndTime - addEndTime) / 100);
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
iterator.next();
}
long end = System.nanoTime();
System.out.println("LinkedList iterator spend time:" + (end - forEndTime) / 100);
}
}
上面的代碼測試了往ArrayList和LinkedList中插入10000個元素,然後分別用for循環遍歷和iterator遍歷所花費的時間。看控制檯打印:
ArrayList insert spend time:14534
ArrayList insertTo spend time:45437 ##新元素都從集合中間增加
ArrayList foreach spend time:55484
ArrayList iterator spend time:12512 ##遍歷所有,iterator還是比foreach快
=============================
LinkedList insert spend time:15932
LinkedList foreach spend time:360552 ##linkedList用for循環遍歷效率是真低呀
LinkedList iterator spend time:13550
下面看看數據量是100000的時候,所花費時間
ArrayList insert spend time:64547
ArrayList insertTo spend time:3093679
ArrayList foreach spend time:3127564
ArrayList iterator spend time:23360
=============================
LinkedList insert spend time:67861
LinkedList foreach spend time:33846313
LinkedList iterator spend time:24305
總結:
- ArrayList如果每次都插入到集合末尾,插入效率和LinkedList差不多;如果ArrayLsit插入的位置隨機,那麼插入效率會比LinkedList差,當數據量變大時,差別會更明顯。
- ArrayList和LinkedList用****iterator遍歷比for循環遍歷快**(數據量很小時,比如幾十,Arraylist用for或者iterator差別不大),當數據量大時,差距更明顯;
- 當數據量大時,最好不要用for循環遍歷LinkedList.
下面貼出ArrayList -> add(int index, Integer element)方法源碼:
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
//元素移動
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
//然後賦值
elementData[index] = element;
size++;
}