1. 程式人生 > >為什麼使用迭代器iterator遍歷Linkedlist要比普通for快

為什麼使用迭代器iterator遍歷Linkedlist要比普通for快


</pre><p></p><pre name="code" class="java">
大家可以搜尋一下普通情況遍歷linkedlist應該是O(n)但是使用iterator就是常數,這讓我很好奇。於是我去查了原始碼。。

一路順著找找到了Collection,確實有一個iterator但是是個interface還沒有實現。

網上找list,有一個listiterator還是這樣。

只能去linked找了,找到了如下原始碼

 	private static final class LinkIterator<ET> implements ListIterator<ET> {
61        int pos, expectedModCount;
62
63        final LinkedList<ET> list;
64
65        Link<ET> link, lastLink;
66
67        LinkIterator(LinkedList<ET> object, int location) {
68            list = object;
69            expectedModCount = list.modCount;
70            if (location >= 0 && location <= list.size) {
71                // pos ends up as -1 if list is empty, it ranges from -1 to
72                // list.size - 1
73                // if link == voidLink then pos must == -1
74                link = list.voidLink;
75                if (location < list.size / 2) {
76                    for (pos = -1; pos + 1 < location; pos++) {
77                        link = link.next;
78                    }
79                } else {
80                    for (pos = list.size; pos >= location; pos--) {
81                        link = link.previous;
82                    }
83                }
84            } else {
85                throw new IndexOutOfBoundsException();
86            }
87        }
88
89        public void add(ET object) {
90            if (expectedModCount == list.modCount) {
91                Link<ET> next = link.next;
92                Link<ET> newLink = new Link<ET>(object, link, next);
93                link.next = newLink;
94                next.previous = newLink;
95                link = newLink;
96                lastLink = null;
97                pos++;
98                expectedModCount++;
99                list.size++;
100                list.modCount++;
101            } else {
102                throw new ConcurrentModificationException();
103            }
104        }
105
106        public boolean hasNext() {
107            return link.next != list.voidLink;
108        }
109
110        public boolean hasPrevious() {
111            return link != list.voidLink;
112        }
113
114        public ET next() {
115            if (expectedModCount == list.modCount) {
116                LinkedList.Link<ET> next = link.next;
117                if (next != list.voidLink) {
118                    lastLink = link = next;
119                    pos++;
120                    return link.data;
121                }
122                throw new NoSuchElementException();
123            }
124            throw new ConcurrentModificationException();
125        }
126
127        public int nextIndex() {
128            return pos + 1;
129        }
130
131        public ET previous() {
132            if (expectedModCount == list.modCount) {
133                if (link != list.voidLink) {
134                    lastLink = link;
135                    link = link.previous;
136                    pos--;
137                    return lastLink.data;
138                }
139                throw new NoSuchElementException();
140            }
141            throw new ConcurrentModificationException();
142        }
143
144        public int previousIndex() {
145            return pos;
146        }
147
148        public void remove() {
149            if (expectedModCount == list.modCount) {
150                if (lastLink != null) {
151                    Link<ET> next = lastLink.next;
152                    Link<ET> previous = lastLink.previous;
153                    next.previous = previous;
154                    previous.next = next;
155                    if (lastLink == link) {
156                        pos--;
157                    }
158                    link = previous;
159                    lastLink = null;
160                    expectedModCount++;
161                    list.size--;
162                    list.modCount++;
163                } else {
164                    throw new IllegalStateException();
165                }
166            } else {
167                throw new ConcurrentModificationException();
168            }
169        }
170
171        public void set(ET object) {
172            if (expectedModCount == list.modCount) {
173                if (lastLink != null) {
174                    lastLink.data = object;
175                } else {
176                    throw new IllegalStateException();
177                }
178            } else {
179                throw new ConcurrentModificationException();
180            }
181        }
182    }
183

我們仔細察看next方法
public ET next() {
115            if (expectedModCount == list.modCount) {
116                LinkedList.Link<ET> next = link.next;
117                if (next != list.voidLink) {
118                    lastLink = link = next;
119                    pos++;
120                    return link.data;
121                }
122                throw new NoSuchElementException();
123            }
124            throw new ConcurrentModificationException();
125        }
126
這裡裡面有一個類是叫link,程式碼如下
private static final class Link<ET> {
49        ET data;
50
51        Link<ET> previous, next;
52
53        Link(ET o, Link<ET> p, Link<ET> n) {
54            data = o;
55            previous = p;
56            next = n;
57        }
58    }
可見list就是一個雙向連結串列的link,沒有什麼特殊之處。到這裡我徹底懵逼了,為什麼呢為什麼呢,為什麼你遍歷就是常數呢?

我們仔細對比一下for迴圈

for(int i =0;i<list.size();i++){
  list.get(i);
}
但是iterator和他對比起來少了一個list.get(i);其實就遍歷而言它們兩個差距並不大。但是其中呼叫了一次get(i).這個時間複雜度應該是O(n)所以巢狀一個for迴圈是O(n^2),但是在iterator中因為next的存在get當前項不需要時間所以迴圈下來應該是O(n),原來差距就在get和iterator這裡了