国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|編程技術(shù)|正則表達(dá)式|

服務(wù)器之家 - 編程語言 - JAVA教程 - Java中ArrayList和LinkedList的遍歷與性能分析

Java中ArrayList和LinkedList的遍歷與性能分析

2020-07-09 11:23daisy JAVA教程

這篇文章主要給大家介紹了ArrayList和LinkedList這兩種list的五種循環(huán)遍歷方式,各種方式的性能測(cè)試對(duì)比,根據(jù)ArrayList和LinkedList的源碼實(shí)現(xiàn)分析性能結(jié)果,總結(jié)結(jié)論。相信對(duì)大家的理解和學(xué)習(xí)具有一定的參考價(jià)值,有需要的朋友們下

前言

通過本文你可以了解List的五種遍歷方式及各自性能和foreach及Iterator的實(shí)現(xiàn),加深對(duì)ArrayListLinkedList實(shí)現(xiàn)的了解。下面來一起看看吧。

一、List的五種遍歷方式

1、for each循環(huán)

?
1
2
3
4
List<Integer> list = new ArrayList<Integer>();
for (Integer j : list) {
 // use j
}

2、顯示調(diào)用集合迭代器

?
1
2
3
4
List<Integer> list = new ArrayList<Integer>();
for (Iterator<Integer> iterator = list.iterator(); iterator.hasNext();) {
 iterator.next();
}

?
1
2
3
4
5
List<Integer> list = new ArrayList<Integer>();
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
 iterator.next();
}

3、下標(biāo)遞增循環(huán),終止條件為每次調(diào)用size()函數(shù)比較判斷

?
1
2
3
4
List<Integer> list = new ArrayList<Integer>();
for (int j = 0; j < list.size(); j++) {
 list.get(j);
}

4、下標(biāo)遞增循環(huán),終止條件為和等于size()的臨時(shí)變量比較判斷

?
1
2
3
4
5
List<Integer> list = new ArrayList<Integer>();
int size = list.size();
for (int j = 0; j < size; j++) {
 list.get(j);
}

5、下標(biāo)遞減循環(huán)

?
1
2
3
4
List<Integer> list = new ArrayList<Integer>();
for (int j = list.size() - 1; j >= 0; j--) {
 list.get(j);
}

List五種遍歷方式的性能測(cè)試及對(duì)比

以下是性能測(cè)試代碼,會(huì)輸出不同數(shù)量級(jí)大小的ArrayList和LinkedList各種遍歷方式所花費(fèi)的時(shí)間。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package cn.trinea.java.test;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
/**
 * JavaLoopTest
 *
 * @author www.trinea.cn 2013-10-28
 */
public class JavaLoopTest {
 public static void main(String[] args) {
  System.out.print("compare loop performance of ArrayList");
  loopListCompare(getArrayLists(10000, 100000, 1000000, 9000000));
  System.out.print("\r\n\r\ncompare loop performance of LinkedList");
  loopListCompare(getLinkedLists(100, 1000, 10000, 100000));
 }
 public static List<Integer>[] getArrayLists(int... sizeArray) {
  List<Integer>[] listArray = new ArrayList[sizeArray.length];
  for (int i = 0; i < listArray.length; i++) {
   int size = sizeArray[i];
   List<Integer> list = new ArrayList<Integer>();
   for (int j = 0; j < size; j++) {
    list.add(j);
   }
   listArray[i] = list;
  }
  return listArray;
 }
 public static List<Integer>[] getLinkedLists(int... sizeArray) {
  List<Integer>[] listArray = new LinkedList[sizeArray.length];
  for (int i = 0; i < listArray.length; i++) {
   int size = sizeArray[i];
   List<Integer> list = new LinkedList<Integer>();
   for (int j = 0; j < size; j++) {
    list.add(j);
   }
   listArray[i] = list;
  }
  return listArray;
 }
 public static void loopListCompare(List<Integer>... listArray) {
  printHeader(listArray);
  long startTime, endTime;
  // Type 1
  for (int i = 0; i < listArray.length; i++) {
   List<Integer> list = listArray[i];
   startTime = Calendar.getInstance().getTimeInMillis();
   for (Integer j : list) {
    // use j
   }
   endTime = Calendar.getInstance().getTimeInMillis();
   printCostTime(i, listArray.length, "for each", endTime - startTime);
  }
  // Type 2
  for (int i = 0; i < listArray.length; i++) {
   List<Integer> list = listArray[i];
   startTime = Calendar.getInstance().getTimeInMillis();
   // Iterator<Integer> iterator = list.iterator();
   // while(iterator.hasNext()) {
   // iterator.next();
   // }
   for (Iterator<Integer> iterator = list.iterator(); iterator.hasNext();) {
    iterator.next();
   }
   endTime = Calendar.getInstance().getTimeInMillis();
   printCostTime(i, listArray.length, "for iterator", endTime - startTime);
  }
  // Type 3
  for (int i = 0; i < listArray.length; i++) {
   List<Integer> list = listArray[i];
   startTime = Calendar.getInstance().getTimeInMillis();
   for (int j = 0; j < list.size(); j++) {
    list.get(j);
   }
   endTime = Calendar.getInstance().getTimeInMillis();
   printCostTime(i, listArray.length, "for list.size()", endTime - startTime);
  }
  // Type 4
  for (int i = 0; i < listArray.length; i++) {
   List<Integer> list = listArray[i];
   startTime = Calendar.getInstance().getTimeInMillis();
   int size = list.size();
   for (int j = 0; j < size; j++) {
    list.get(j);
   }
   endTime = Calendar.getInstance().getTimeInMillis();
   printCostTime(i, listArray.length, "for size = list.size()", endTime - startTime);
  }
  // Type 5
  for (int i = 0; i < listArray.length; i++) {
   List<Integer> list = listArray[i];
   startTime = Calendar.getInstance().getTimeInMillis();
   for (int j = list.size() - 1; j >= 0; j--) {
    list.get(j);
   }
   endTime = Calendar.getInstance().getTimeInMillis();
   printCostTime(i, listArray.length, "for j--", endTime - startTime);
  }
 }
 static int     FIRST_COLUMN_LENGTH = 23, OTHER_COLUMN_LENGTH = 12, TOTAL_COLUMN_LENGTH = 71;
 static final DecimalFormat COMMA_FORMAT  = new DecimalFormat("#,###");
 public static void printHeader(List<Integer>... listArray) {
  printRowDivider();
  for (int i = 0; i < listArray.length; i++) {
   if (i == 0) {
    StringBuilder sb = new StringBuilder().append("list size");
    while (sb.length() < FIRST_COLUMN_LENGTH) {
     sb.append(" ");
    }
    System.out.print(sb);
   }
   StringBuilder sb = new StringBuilder().append("| ").append(COMMA_FORMAT.format(listArray[i].size()));
   while (sb.length() < OTHER_COLUMN_LENGTH) {
    sb.append(" ");
   }
   System.out.print(sb);
  }
  TOTAL_COLUMN_LENGTH = FIRST_COLUMN_LENGTH + OTHER_COLUMN_LENGTH * listArray.length;
  printRowDivider();
 }
 public static void printRowDivider() {
  System.out.println();
  StringBuilder sb = new StringBuilder();
  while (sb.length() < TOTAL_COLUMN_LENGTH) {
   sb.append("-");
  }
  System.out.println(sb);
 }
 public static void printCostTime(int i, int size, String caseName, long costTime) {
  if (i == 0) {
   StringBuilder sb = new StringBuilder().append(caseName);
   while (sb.length() < FIRST_COLUMN_LENGTH) {
    sb.append(" ");
   }
   System.out.print(sb);
  }
  StringBuilder sb = new StringBuilder().append("| ").append(costTime).append(" ms");
  while (sb.length() < OTHER_COLUMN_LENGTH) {
   sb.append(" ");
  }
  System.out.print(sb);
  if (i == size - 1) {
   printRowDivider();
  }
 }
}

PS:如果運(yùn)行報(bào)異常in thread “main” java.lang.OutOfMemoryError: Java heap space,請(qǐng)將main函數(shù)里面list size的大小減小。

其中getArrayLists函數(shù)會(huì)返回不同size的ArrayList,getLinkedLists函數(shù)會(huì)返回不同size的LinkedList。

loopListCompare函數(shù)會(huì)分別用上面的遍歷方式1-5去遍歷每一個(gè)list數(shù)組(包含不同大小list)中的list。

print開頭函數(shù)為輸出輔助函數(shù)。

測(cè)試環(huán)境為Windows7 32位系統(tǒng) 3.2G雙核CPU 4G內(nèi)存,Java 7,Eclipse -Xms512m -Xmx512m

最終測(cè)試結(jié)果如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
compare loop performance of ArrayList
-----------------------------------------------------------------------
list size    | 10,000 | 100,000 | 1,000,000 | 10,000,000
-----------------------------------------------------------------------
for each    | 1 ms  | 3 ms  | 14 ms  | 152 ms
-----------------------------------------------------------------------
for iterator   | 0 ms  | 1 ms  | 12 ms  | 114 ms
-----------------------------------------------------------------------
for list.size()  | 1 ms  | 1 ms  | 13 ms  | 128 ms
-----------------------------------------------------------------------
for size = list.size() | 0 ms  | 0 ms  | 6 ms  | 62 ms 
-----------------------------------------------------------------------
for j--    | 0 ms  | 1 ms  | 6 ms  | 63 ms 
-----------------------------------------------------------------------
 
compare loop performance of LinkedList
-----------------------------------------------------------------------
list size    | 100  | 1,000  | 10,000 | 100,000
-----------------------------------------------------------------------
for each    | 0 ms  | 1 ms  | 1 ms  | 2 ms 
-----------------------------------------------------------------------
for iterator   | 0 ms  | 0 ms  | 0 ms  | 2 ms 
-----------------------------------------------------------------------
for list.size()  | 0 ms  | 1 ms  | 73 ms  | 7972 ms
-----------------------------------------------------------------------
for size = list.size() | 0 ms  | 0 ms  | 67 ms  | 8216 ms
-----------------------------------------------------------------------
for j--    | 0 ms  | 1 ms  | 67 ms  | 8277 ms
-----------------------------------------------------------------------

第一張表為ArrayList對(duì)比結(jié)果,第二張表為LinkedList對(duì)比結(jié)果。

表橫向?yàn)橥槐闅v方式不同大小list遍歷的時(shí)間消耗,縱向?yàn)橥籰ist不同遍歷方式遍歷的時(shí)間消耗。

PS:由于首次遍歷List會(huì)稍微多耗時(shí)一點(diǎn),for each的結(jié)果稍微有點(diǎn)偏差,將測(cè)試代碼中的幾個(gè)Type順序調(diào)換會(huì)發(fā)現(xiàn),for each耗時(shí)和for iterator接近。

遍歷方式性能測(cè)試結(jié)果分析

1、foreach介紹

foreach是Java SE5.0引入的功能很強(qiáng)的循環(huán)結(jié)構(gòu),for (Integer j : list)應(yīng)讀作for each int in list。

for (Integer j : list)實(shí)現(xiàn)幾乎等價(jià)于

?
1
2
3
4
Iterator<Integer> iterator = list.iterator();
while(iterator.hasNext()) {
 Integer j = iterator.next();
}

foreach代碼書寫簡單,不必關(guān)心下標(biāo)初始值和終止值及越界等,所以不易出錯(cuò)

2、ArrayList遍歷方式結(jié)果分析

a. 在ArrayList大小為十萬之前,五種遍歷方式時(shí)間消耗幾乎一樣

b. 在十萬以后,第四、五種遍歷方式快于前三種,get方式優(yōu)于Iterator方式,并且

?
1
2
3
4
int size = list.size();
for (int j = 0; j < size; j++) {
 list.get(j);
}

用臨時(shí)變量size取代list.size()性能更優(yōu)。我們看看ArrayList中迭代器Iteratorget方法的實(shí)現(xiàn)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
private class Itr implements Iterator<E> {
 int cursor;  // index of next element to return
 int lastRet = -1; // index of last element returned; -1 if no such
 int expectedModCount = modCount;
 
 public boolean hasNext() {
  return cursor != size;
 }
 
 @SuppressWarnings("unchecked")
 public E next() {
  checkForComodification();
  int i = cursor;
  if (i >= size)
   throw new NoSuchElementException();
  Object[] elementData = ArrayList.this.elementData;
  if (i >= elementData.length)
   throw new ConcurrentModificationException();
  cursor = i + 1;
  return (E) elementData[lastRet = i];
 }
 ……
}
 
public E get(int index) {
 rangeCheck(index);
 
 return elementData(index);
}

從中可以看出getIteratornext函數(shù)同樣通過直接定位數(shù)據(jù)獲取元素,只是多了幾個(gè)判斷而已。

c. 從上可以看出即便在千萬大小的ArrayList中,幾種遍歷方式相差也不過50ms左右,且在常用的十萬左右時(shí)間幾乎相等,考慮foreach的優(yōu)點(diǎn),我們大可選用foreach這種簡便方式進(jìn)行遍歷。

3、LinkedList遍歷方式結(jié)果分析

a. 在LinkedList大小接近一萬時(shí),get方式和Iterator方式就已經(jīng)差了差不多兩個(gè)數(shù)量級(jí),十萬時(shí)Iterator方式性能已經(jīng)遠(yuǎn)勝于get方式。

我們看看LinkedList中迭代器和get方法的實(shí)現(xiàn)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
private class ListItr implements ListIterator<E> {
 private Node<E> lastReturned = null;
 private Node<E> next;
 private int nextIndex;
 private int expectedModCount = modCount;
 
 ListItr(int index) {
  // assert isPositionIndex(index);
  next = (index == size) ? null : node(index);
  nextIndex = index;
 }
 
 public boolean hasNext() {
  return nextIndex < size;
 }
 
 public E next() {
  checkForComodification();
  if (!hasNext())
   throw new NoSuchElementException();
 
  lastReturned = next;
  next = next.next;
  nextIndex++;
  return lastReturned.item;
 }
 ……
}
 
public E get(int index) {
 checkElementIndex(index);
 return node(index).item;
}
 
/**
 * Returns the (non-null) Node at the specified element index.
 */
Node<E> node(int index) {
 // assert isElementIndex(index);
 
 if (index < (size >> 1)) {
  Node<E> x = first;
  for (int i = 0; i < index; i++)
   x = x.next;
  return x;
 } else {
  Node<E> x = last;
  for (int i = size - 1; i > index; i--)
   x = x.prev;
  return x;
 }
}

從上面代碼中可以看出LinkedList迭代器的next函數(shù)只是通過next指針快速得到下一個(gè)元素并返回。而get方法會(huì)從頭遍歷直到index下標(biāo),查找一個(gè)元素時(shí)間復(fù)雜度為哦O(n),遍歷的時(shí)間復(fù)雜度就達(dá)到了O(n2)。

所以對(duì)于LinkedList的遍歷推薦使用foreach,避免使用get方式遍歷。

4、ArrayList和LinkedList遍歷方式結(jié)果對(duì)比分析

從上面的數(shù)量級(jí)來看,同樣是foreach循環(huán)遍歷,ArrayList和LinkedList時(shí)間差不多,可將本例稍作修改加大list size會(huì)發(fā)現(xiàn)兩者基本在一個(gè)數(shù)量級(jí)上。

ArrayList get函數(shù)直接定位獲取的方式時(shí)間復(fù)雜度為O(1),而LinkedList的get函數(shù)時(shí)間復(fù)雜度為O(n)。

再結(jié)合考慮空間消耗的話,建議首選ArrayList。對(duì)于個(gè)別插入刪除非常多的可以使用LinkedList。

結(jié)論總結(jié)

通過上面的分析我們基本可以總結(jié)下:

  1. 無論ArrayList還是LinkedList,遍歷建議使用foreach,尤其是數(shù)據(jù)量較大時(shí)LinkedList避免使用get遍歷。
  2. List使用首選ArrayList。對(duì)于個(gè)別插入刪除非常多的可以使用LinkedList。
  3. 可能在遍歷List循環(huán)內(nèi)部需要使用到下標(biāo),這時(shí)綜合考慮下是使用foreach和自增count還是get方式。

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對(duì)大家學(xué)習(xí)或者使用Java的時(shí)候能有所幫助,如果有疑問大家可以留言交流。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 亚洲精品免费看 | 久久精品日产第一区二区三区 | 99免费视频 | 欧洲精品码一区二区三区免费看 | 亚洲成人精品一区 | 久久久久999| 毛片综合 | 人人澡人人爽 | 欧美一级裸体视频 | 精品国产一区二区国模嫣然 | 在线观看视频黄 | 最新高清无码专区 | 国产做a爰片久久毛片a我的朋友 | 日本网站在线免费观看 | 久草在线资源福利站 | 久久99亚洲精品 | 中文字幕精品一区 | 精品香蕉一区二区三区 | 日韩一区二区影视 | 日韩美女av在线 | 亚洲蜜桃妇女 | www.午夜| 国产精品美乳在线观看 | 久久久久久亚洲一区二区三区蜜臀 | 国产精品网站在线观看 | 日韩视频不卡 | 国产乱码久久久久久一区二区 | 久久久亚洲国产天美传媒修理工 | 99re热精品视频 | 国产综合视频 | 亚洲视频二区 | 九色在线 | 中文字幕91 | av在线一区二区 | 国产成人精品久久二区二区91 | 日韩小视频网站 | 欧美一区| 嫩草影院黄色 | 久久综合伊人77777蜜臀 | 五月天伊人 | 亚洲三区在线观看 |