1 |
/* LinkedList.java -- Linked list implementation of the List interface |
/* LinkedList.java -- Linked list implementation of the List interface |
2 |
Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. |
Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. |
3 |
|
|
4 |
This file is part of GNU Classpath. |
This file is part of GNU Classpath. |
5 |
|
|
32 |
import java.io.IOException; |
import java.io.IOException; |
33 |
import java.lang.reflect.Array; |
import java.lang.reflect.Array; |
34 |
|
|
|
// TO DO: |
|
|
// ~ Doc comment for the class. |
|
|
// ~ Doc comments for the non-list methods. |
|
|
// ~ other general implementation notes. |
|
|
|
|
35 |
/** |
/** |
36 |
* Linked list implementation of the List interface. |
* Linked list implementation of the List interface. In addition to the |
37 |
|
* methods of the List interface, this class provides access to the first |
38 |
|
* and last list elements in O(1) time for easy stack, queue, or double-ended |
39 |
|
* queue (deque) creation. The list is doubly-linked, with traversal to a |
40 |
|
* given index starting from the end closest to the element.<p> |
41 |
|
* |
42 |
|
* LinkedList is not synchronized, so if you need multi-threaded access, |
43 |
|
* consider using:<br> |
44 |
|
* <code>List l = Collections.synchronizedList(new LinkedList(...));</code> |
45 |
|
* <p> |
46 |
|
* |
47 |
|
* The iterators are <i>fail-fast</i>, meaning that any structural |
48 |
|
* modification, except for <code>remove()</code> called on the iterator |
49 |
|
* itself, cause the iterator to throw a |
50 |
|
* {@link ConcurrentModificationException} rather than exhibit |
51 |
|
* non-deterministic behavior. |
52 |
|
* |
53 |
|
* @author Original author unknown |
54 |
|
* @author Eric Blake <ebb9@email.byu.edu> |
55 |
|
* @see List |
56 |
|
* @see ArrayList |
57 |
|
* @see Vector |
58 |
|
* @see Collections#synchronizedList(List) |
59 |
|
* @since 1.2 |
60 |
|
* @status missing javadoc, but complete to 1.4 |
61 |
*/ |
*/ |
62 |
public class LinkedList extends AbstractSequentialList |
public class LinkedList extends AbstractSequentialList |
63 |
implements List, Cloneable, Serializable |
implements List, Cloneable, Serializable |
64 |
{ |
{ |
65 |
static final long serialVersionUID = 876323262645176354L; |
/** |
66 |
|
* Compatible with JDK 1.2. |
67 |
|
*/ |
68 |
|
private static final long serialVersionUID = 876323262645176354L; |
69 |
|
|
70 |
/** |
/** |
71 |
* An Entry containing the head (in the next field) and the tail (in the |
* The first element in the list. |
|
* previous field) of the list. The data field is null. If the list is empty, |
|
|
* both the head and the tail point to ends itself. |
|
72 |
*/ |
*/ |
73 |
transient Entry first; |
transient Entry first; |
74 |
|
|
75 |
|
/** |
76 |
|
* The last element in the list. |
77 |
|
*/ |
78 |
transient Entry last; |
transient Entry last; |
79 |
|
|
80 |
/** |
/** |
85 |
/** |
/** |
86 |
* Class to represent an entry in the list. Holds a single element. |
* Class to represent an entry in the list. Holds a single element. |
87 |
*/ |
*/ |
88 |
private static class Entry |
private static final class Entry |
89 |
{ |
{ |
90 |
|
/** The element in the list. */ |
91 |
Object data; |
Object data; |
92 |
|
|
93 |
|
/** The next list entry, null if this is last. */ |
94 |
Entry next; |
Entry next; |
95 |
|
|
96 |
|
/** The previous list entry, null if this is first. */ |
97 |
Entry previous; |
Entry previous; |
98 |
|
|
99 |
|
/** |
100 |
|
* Construct an entry. |
101 |
|
* @param data the list element |
102 |
|
*/ |
103 |
Entry(Object data) |
Entry(Object data) |
104 |
{ |
{ |
105 |
this.data = data; |
this.data = data; |
106 |
} |
} |
107 |
} |
} // class Entry |
108 |
|
|
109 |
/** |
/** |
110 |
* Obtain the Entry at a given position in a list. This method of course |
* Obtain the Entry at a given position in a list. This method of course |
111 |
* takes linear time, but it is intelligent enough to take the shorter of the |
* takes linear time, but it is intelligent enough to take the shorter of the |
115 |
* For speed and flexibility, range checking is not done in this method: |
* For speed and flexibility, range checking is not done in this method: |
116 |
* Incorrect values will be returned if (n < 0) or (n >= size). |
* Incorrect values will be returned if (n < 0) or (n >= size). |
117 |
* |
* |
118 |
* @param n the number of the entry to get. |
* @param n the number of the entry to get |
119 |
|
* @return the entry at position n |
120 |
*/ |
*/ |
121 |
private Entry getEntry(int n) |
private Entry getEntry(int n) |
122 |
{ |
{ |
124 |
if (n < size / 2) |
if (n < size / 2) |
125 |
{ |
{ |
126 |
e = first; |
e = first; |
127 |
// n less than size/2, iterate from start |
// n less than size/2, iterate from start |
128 |
while (n-- > 0) |
while (n-- > 0) |
129 |
{ |
e = e.next; |
|
e = e.next; |
|
|
} |
|
130 |
} |
} |
131 |
else |
else |
132 |
{ |
{ |
133 |
e = last; |
e = last; |
134 |
// n greater than size/2, iterate from end |
// n greater than size/2, iterate from end |
135 |
while (++n < size) |
while (++n < size) |
136 |
{ |
e = e.previous; |
|
e = e.previous; |
|
|
} |
|
137 |
} |
} |
138 |
return e; |
return e; |
139 |
} |
} |
140 |
|
|
141 |
/** Remove an entry from the list. This will adjust size and deal with |
/** |
142 |
* `first' and `last' appropriatly. It does not effect modCount, that is |
* Remove an entry from the list. This will adjust size and deal with |
143 |
* the responsibility of the caller. */ |
* `first' and `last' appropriatly. |
144 |
|
* |
145 |
|
* @param e the entry to remove |
146 |
|
*/ |
147 |
private void removeEntry(Entry e) |
private void removeEntry(Entry e) |
148 |
{ |
{ |
149 |
if (size == 1) |
modCount++; |
150 |
|
size--; |
151 |
|
if (size == 0) |
152 |
first = last = null; |
first = last = null; |
153 |
else |
else |
154 |
{ |
{ |
155 |
if (e == first) |
if (e == first) |
156 |
{ |
{ |
157 |
first = e.next; |
first = e.next; |
158 |
e.next.previous = null; |
e.next.previous = null; |
159 |
} |
} |
160 |
else if (e == last) |
else if (e == last) |
161 |
{ |
{ |
162 |
last = e.previous; |
last = e.previous; |
163 |
e.previous.next = null; |
e.previous.next = null; |
164 |
} |
} |
165 |
else |
else |
166 |
{ |
{ |
167 |
e.next.previous = e.previous; |
e.next.previous = e.previous; |
168 |
e.previous.next = e.next; |
e.previous.next = e.next; |
169 |
} |
} |
170 |
} |
} |
171 |
size--; |
} |
172 |
|
|
173 |
|
/** |
174 |
|
* Checks that the index is in the range of possible elements (inclusive). |
175 |
|
* |
176 |
|
* @param index the index to check |
177 |
|
* @throws IndexOutOfBoundsException if index < 0 || index > size |
178 |
|
*/ |
179 |
|
private void rangeInclusive(int index) |
180 |
|
{ |
181 |
|
if (index < 0 || index > size) |
182 |
|
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" |
183 |
|
+ size); |
184 |
|
} |
185 |
|
|
186 |
|
/** |
187 |
|
* Checks that the index is in the range of existing elements (exclusive). |
188 |
|
* |
189 |
|
* @param index the index to check |
190 |
|
* @throws IndexOutOfBoundsException if index < 0 || index >= size |
191 |
|
*/ |
192 |
|
private void rangeExclusive(int index) |
193 |
|
{ |
194 |
|
if (index < 0 || index >= size) |
195 |
|
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" |
196 |
|
+ size); |
197 |
} |
} |
198 |
|
|
199 |
/** |
/** |
201 |
*/ |
*/ |
202 |
public LinkedList() |
public LinkedList() |
203 |
{ |
{ |
|
super(); |
|
204 |
} |
} |
205 |
|
|
206 |
/** |
/** |
207 |
* Create a linked list containing the elements, in order, of a given |
* Create a linked list containing the elements, in order, of a given |
208 |
* collection. |
* collection. |
209 |
* |
* |
210 |
* @param c the collection to populate this list from. |
* @param c the collection to populate this list from |
211 |
|
* @throws NullPointerException if c is null |
212 |
*/ |
*/ |
213 |
public LinkedList(Collection c) |
public LinkedList(Collection c) |
214 |
{ |
{ |
|
super(); |
|
|
// Note: addAll could be made slightly faster, but not enough so to justify |
|
|
// re-implementing it from scratch. It is just a matter of a relatively |
|
|
// small constant factor. |
|
215 |
addAll(c); |
addAll(c); |
216 |
} |
} |
217 |
|
|
218 |
|
/** |
219 |
|
* Returns the first element in the list. |
220 |
|
* |
221 |
|
* @return the first list element |
222 |
|
* @throws NoSuchElementException if the list is empty |
223 |
|
*/ |
224 |
public Object getFirst() |
public Object getFirst() |
225 |
{ |
{ |
226 |
if (size == 0) |
if (size == 0) |
228 |
return first.data; |
return first.data; |
229 |
} |
} |
230 |
|
|
231 |
|
/** |
232 |
|
* Returns the last element in the list. |
233 |
|
* |
234 |
|
* @return the last list element |
235 |
|
* @throws NoSuchElementException if the list is empty |
236 |
|
*/ |
237 |
public Object getLast() |
public Object getLast() |
238 |
{ |
{ |
239 |
if (size == 0) |
if (size == 0) |
241 |
return last.data; |
return last.data; |
242 |
} |
} |
243 |
|
|
244 |
|
/** |
245 |
|
* Remove and return the first element in the list. |
246 |
|
* |
247 |
|
* @return the former first element in the list |
248 |
|
* @throws NoSuchElementException if the list is empty |
249 |
|
*/ |
250 |
public Object removeFirst() |
public Object removeFirst() |
251 |
{ |
{ |
252 |
if (size == 0) |
if (size == 0) |
253 |
throw new NoSuchElementException(); |
throw new NoSuchElementException(); |
|
size--; |
|
254 |
modCount++; |
modCount++; |
255 |
|
size--; |
256 |
Object r = first.data; |
Object r = first.data; |
257 |
|
|
258 |
if (first.next != null) |
if (first.next != null) |
259 |
first.next.previous = null; |
first.next.previous = null; |
260 |
else |
else |
261 |
last = null; |
last = null; |
262 |
|
|
263 |
first = first.next; |
first = first.next; |
264 |
|
|
265 |
return r; |
return r; |
266 |
} |
} |
267 |
|
|
268 |
|
/** |
269 |
|
* Remove and return the last element in the list. |
270 |
|
* |
271 |
|
* @return the former last element in the list |
272 |
|
* @throws NoSuchElementException if the list is empty |
273 |
|
*/ |
274 |
public Object removeLast() |
public Object removeLast() |
275 |
{ |
{ |
276 |
if (size == 0) |
if (size == 0) |
277 |
throw new NoSuchElementException(); |
throw new NoSuchElementException(); |
|
size--; |
|
278 |
modCount++; |
modCount++; |
279 |
|
size--; |
280 |
Object r = last.data; |
Object r = last.data; |
281 |
|
|
282 |
if (last.previous != null) |
if (last.previous != null) |
283 |
last.previous.next = null; |
last.previous.next = null; |
284 |
else |
else |
285 |
first = null; |
first = null; |
286 |
|
|
287 |
last = last.previous; |
last = last.previous; |
288 |
|
|
289 |
return r; |
return r; |
290 |
} |
} |
291 |
|
|
292 |
|
/** |
293 |
|
* Insert an element at the first of the list. |
294 |
|
* |
295 |
|
* @param o the element to insert |
296 |
|
*/ |
297 |
public void addFirst(Object o) |
public void addFirst(Object o) |
298 |
{ |
{ |
|
modCount++; |
|
299 |
Entry e = new Entry(o); |
Entry e = new Entry(o); |
300 |
|
|
301 |
if (size == 0) |
modCount++; |
302 |
|
size++; |
303 |
|
if (size == 1) |
304 |
first = last = e; |
first = last = e; |
305 |
else |
else |
306 |
{ |
{ |
307 |
e.next = first; |
e.next = first; |
308 |
first.previous = e; |
first.previous = e; |
309 |
first = e; |
first = e; |
310 |
} |
} |
|
size++; |
|
311 |
} |
} |
312 |
|
|
313 |
|
/** |
314 |
|
* Insert an element at the last of the list. |
315 |
|
* |
316 |
|
* @param o the element to insert |
317 |
|
*/ |
318 |
public void addLast(Object o) |
public void addLast(Object o) |
319 |
{ |
{ |
|
modCount++; |
|
320 |
addLastEntry(new Entry(o)); |
addLastEntry(new Entry(o)); |
321 |
} |
} |
322 |
|
|
323 |
|
/** |
324 |
|
* Inserts an element at the end of the list. |
325 |
|
* |
326 |
|
* @param e the entry to add |
327 |
|
*/ |
328 |
private void addLastEntry(Entry e) |
private void addLastEntry(Entry e) |
329 |
{ |
{ |
330 |
|
modCount++; |
331 |
|
size++; |
332 |
if (size == 0) |
if (size == 0) |
333 |
first = last = e; |
first = last = e; |
334 |
else |
else |
335 |
{ |
{ |
336 |
e.previous = last; |
e.previous = last; |
337 |
last.next = e; |
last.next = e; |
338 |
last = e; |
last = e; |
339 |
} |
} |
|
size++; |
|
340 |
} |
} |
341 |
|
|
342 |
|
/** |
343 |
|
* Returns true if the list contains the given object. Comparison is done by |
344 |
|
* <code>o == null ? e = null : o.equals(e)</code>. |
345 |
|
* |
346 |
|
* @param o the element to look for |
347 |
|
* @return true if it is found |
348 |
|
*/ |
349 |
public boolean contains(Object o) |
public boolean contains(Object o) |
350 |
{ |
{ |
351 |
Entry e = first; |
Entry e = first; |
352 |
while (e != null) |
while (e != null) |
353 |
{ |
{ |
354 |
if (e.data == null ? o == null : o.equals(e.data)) |
if (equals(o, e.data)) |
355 |
return true; |
return true; |
356 |
e = e.next; |
e = e.next; |
357 |
} |
} |
358 |
return false; |
return false; |
359 |
} |
} |
360 |
|
|
361 |
|
/** |
362 |
|
* Returns the size of the list. |
363 |
|
* |
364 |
|
* @return the list size |
365 |
|
*/ |
366 |
public int size() |
public int size() |
367 |
{ |
{ |
368 |
return size; |
return size; |
369 |
} |
} |
370 |
|
|
371 |
|
/** |
372 |
|
* Adds an element to the end of the list. |
373 |
|
* |
374 |
|
* @param e the entry to add |
375 |
|
* @return true, as it always succeeds |
376 |
|
*/ |
377 |
public boolean add(Object o) |
public boolean add(Object o) |
378 |
{ |
{ |
|
modCount++; |
|
379 |
addLastEntry(new Entry(o)); |
addLastEntry(new Entry(o)); |
380 |
return true; |
return true; |
381 |
} |
} |
382 |
|
|
383 |
|
/** |
384 |
|
* Removes the entry at the lowest index in the list that matches the given |
385 |
|
* object, comparing by <code>o == null ? e = null : o.equals(e)</code>. |
386 |
|
* |
387 |
|
* @param o the object to remove |
388 |
|
* @return true if an instance of the object was removed |
389 |
|
*/ |
390 |
public boolean remove(Object o) |
public boolean remove(Object o) |
391 |
{ |
{ |
|
modCount++; |
|
392 |
Entry e = first; |
Entry e = first; |
393 |
while (e != null) |
while (e != null) |
394 |
{ |
{ |
395 |
if (e.data == null ? o == null : o.equals(e.data)) |
if (equals(o, e.data)) |
396 |
{ |
{ |
397 |
removeEntry(e); |
removeEntry(e); |
398 |
return true; |
return true; |
399 |
} |
} |
400 |
e = e.next; |
e = e.next; |
401 |
} |
} |
402 |
return false; |
return false; |
403 |
} |
} |
404 |
|
|
405 |
|
/** |
406 |
|
* Append the elements of the collection in iteration order to the end of |
407 |
|
* this list. If this list is modified externally (for example, if this |
408 |
|
* list is the collection), behavior is unspecified. |
409 |
|
* |
410 |
|
* @param c the collection to append |
411 |
|
* @return true if the list was modified |
412 |
|
* @throws NullPointerException if c is null |
413 |
|
*/ |
414 |
public boolean addAll(Collection c) |
public boolean addAll(Collection c) |
415 |
{ |
{ |
416 |
return addAll(size, c); |
return addAll(size, c); |
417 |
} |
} |
418 |
|
|
419 |
|
/** |
420 |
|
* Insert the elements of the collection in iteration order at the given |
421 |
|
* index of this list. If this list is modified externally (for example, |
422 |
|
* if this list is the collection), behavior is unspecified. |
423 |
|
* |
424 |
|
* @param c the collection to append |
425 |
|
* @return true if the list was modified |
426 |
|
* @throws NullPointerException if c is null |
427 |
|
* @throws IndexOutOfBoundsException if index < 0 || index > size() |
428 |
|
*/ |
429 |
public boolean addAll(int index, Collection c) |
public boolean addAll(int index, Collection c) |
430 |
{ |
{ |
431 |
if (index < 0 || index > size) |
rangeInclusive(index); |
|
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + |
|
|
size); |
|
|
modCount++; |
|
432 |
int csize = c.size(); |
int csize = c.size(); |
433 |
|
|
434 |
if (csize == 0) |
if (csize == 0) |
435 |
return false; |
return false; |
436 |
|
|
437 |
Iterator itr = c.iterator(); |
Iterator itr = c.iterator(); |
438 |
|
|
439 |
// Get the entries just before and after index. If index is at the start |
// Get the entries just before and after index. If index is at the start |
440 |
// of the list, BEFORE is null. If index is at the end of thelist, AFTER is |
// of the list, BEFORE is null. If index is at the end of the list, AFTER |
441 |
// null. If the list is empty, both are null. |
// is null. If the list is empty, both are null. |
442 |
Entry after = null; |
Entry after = null; |
443 |
Entry before = null; |
Entry before = null; |
444 |
if (index != size) |
if (index != size) |
445 |
{ |
{ |
446 |
after = getEntry(index); |
after = getEntry(index); |
447 |
before = after.previous; |
before = after.previous; |
448 |
} |
} |
449 |
else |
else |
450 |
before = last; |
before = last; |
451 |
|
|
452 |
// Create the first new entry. We do not yet set the link from `before' |
// Create the first new entry. We do not yet set the link from `before' |
453 |
// to the first entry, in order to deal with the case where (c == this). |
// to the first entry, in order to deal with the case where (c == this). |
454 |
// [Actually, we don't have to handle this case to fufill the |
// [Actually, we don't have to handle this case to fufill the |
455 |
// contract for addAll(), but Sun's implementation appears to.] |
// contract for addAll(), but Sun's implementation appears to.] |
456 |
Entry e = new Entry(itr.next()); |
Entry e = new Entry(itr.next()); |
457 |
e.previous = before; |
e.previous = before; |
458 |
Entry prev = e; |
Entry prev = e; |
459 |
Entry firstNew = e; |
Entry firstNew = e; |
460 |
|
|
461 |
// Create and link all the remaining entries. |
// Create and link all the remaining entries. |
462 |
for (int pos = 1; pos < csize; pos++) |
for (int pos = 1; pos < csize; pos++) |
463 |
{ |
{ |
464 |
e = new Entry(itr.next()); |
e = new Entry(itr.next()); |
465 |
e.previous = prev; |
e.previous = prev; |
466 |
prev.next = e; |
prev.next = e; |
467 |
prev = e; |
prev = e; |
468 |
} |
} |
469 |
|
|
470 |
// Link the new chain of entries into the list. |
// Link the new chain of entries into the list. |
471 |
|
modCount++; |
472 |
|
size += csize; |
473 |
prev.next = after; |
prev.next = after; |
474 |
if (after != null) |
if (after != null) |
475 |
after.previous = e; |
after.previous = e; |
476 |
else |
else |
477 |
last = e; |
last = e; |
478 |
|
|
479 |
if (before != null) |
if (before != null) |
480 |
before.next = firstNew; |
before.next = firstNew; |
481 |
else |
else |
482 |
first = firstNew; |
first = firstNew; |
|
|
|
|
size += csize; |
|
483 |
return true; |
return true; |
484 |
} |
} |
485 |
|
|
486 |
|
/** |
487 |
|
* Remove all elements from this list. |
488 |
|
*/ |
489 |
public void clear() |
public void clear() |
490 |
{ |
{ |
491 |
modCount++; |
if (size > 0) |
492 |
first = null; |
{ |
493 |
last = null; |
modCount++; |
494 |
size = 0; |
first = null; |
495 |
|
last = null; |
496 |
|
size = 0; |
497 |
|
} |
498 |
} |
} |
499 |
|
|
500 |
|
/** |
501 |
|
* Return the element at index. |
502 |
|
* |
503 |
|
* @param index the place to look |
504 |
|
* @return the element at index |
505 |
|
* @throws IndexOutOfBoundsException if index < 0 || index >= size() |
506 |
|
*/ |
507 |
public Object get(int index) |
public Object get(int index) |
508 |
{ |
{ |
509 |
if (index < 0 || index >= size) |
rangeExclusive(index); |
510 |
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + |
return getEntry(index).data; |
|
size); |
|
|
Entry e = getEntry(index); |
|
|
return e.data; |
|
511 |
} |
} |
512 |
|
|
513 |
|
/** |
514 |
|
* Replace the element at the given location in the list. |
515 |
|
* |
516 |
|
* @param index which index to change |
517 |
|
* @param o the new element |
518 |
|
* @return the prior element |
519 |
|
* @throws IndexOutOfBoundsException if index < 0 || index >= size() |
520 |
|
*/ |
521 |
public Object set(int index, Object o) |
public Object set(int index, Object o) |
522 |
{ |
{ |
523 |
if (index < 0 || index >= size) |
rangeExclusive(index); |
|
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + |
|
|
size); |
|
524 |
Entry e = getEntry(index); |
Entry e = getEntry(index); |
525 |
Object old = e.data; |
Object old = e.data; |
526 |
e.data = o; |
e.data = o; |
527 |
return old; |
return old; |
528 |
} |
} |
529 |
|
|
530 |
|
/** |
531 |
|
* Inserts an element in the given position in the list. |
532 |
|
* |
533 |
|
* @param index where to insert the element |
534 |
|
* @param o the element to insert |
535 |
|
* @throws IndexOutOfBoundsException if index < 0 || index > size() |
536 |
|
*/ |
537 |
public void add(int index, Object o) |
public void add(int index, Object o) |
538 |
{ |
{ |
539 |
if (index < 0 || index > size) |
rangeInclusive(index); |
540 |
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + |
Entry e = new Entry(o); |
541 |
size); |
|
|
modCount++; |
|
|
addEntry(index, new Entry(o)); |
|
|
} |
|
|
|
|
|
private void addEntry(int index, Entry e) |
|
|
{ |
|
542 |
if (index < size) |
if (index < size) |
543 |
{ |
{ |
544 |
Entry after = getEntry(index); |
modCount++; |
545 |
e.next = after; |
size++; |
546 |
e.previous = after.previous; |
Entry after = getEntry(index); |
547 |
if (after.previous == null) |
e.next = after; |
548 |
first = e; |
e.previous = after.previous; |
549 |
else |
if (after.previous == null) |
550 |
after.previous.next = e; |
first = e; |
551 |
after.previous = e; |
else |
552 |
size++; |
after.previous.next = e; |
553 |
|
after.previous = e; |
554 |
} |
} |
555 |
else |
else |
556 |
addLastEntry(e); |
addLastEntry(e); |
557 |
} |
} |
558 |
|
|
559 |
|
/** |
560 |
|
* Removes the element at the given position from the list. |
561 |
|
* |
562 |
|
* @param index the location of the element to remove |
563 |
|
* @return the removed element |
564 |
|
* @throws IndexOutOfBoundsException if index < 0 || index > size() |
565 |
|
*/ |
566 |
public Object remove(int index) |
public Object remove(int index) |
567 |
{ |
{ |
568 |
if (index < 0 || index >= size) |
rangeExclusive(index); |
|
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + |
|
|
size); |
|
|
modCount++; |
|
569 |
Entry e = getEntry(index); |
Entry e = getEntry(index); |
570 |
removeEntry(e); |
removeEntry(e); |
571 |
return e.data; |
return e.data; |
572 |
} |
} |
573 |
|
|
574 |
|
/** |
575 |
|
* Returns the first index where the element is located in the list, or -1. |
576 |
|
* |
577 |
|
* @param o the element to look for |
578 |
|
* @return its position, or -1 if not found |
579 |
|
*/ |
580 |
public int indexOf(Object o) |
public int indexOf(Object o) |
581 |
{ |
{ |
582 |
int index = 0; |
int index = 0; |
583 |
Entry e = first; |
Entry e = first; |
584 |
while (e != null) |
while (e != null) |
585 |
{ |
{ |
586 |
if (e.data == null ? o == null : o.equals(e.data)) |
if (equals(o, e.data)) |
587 |
return index; |
return index; |
588 |
++index; |
index++; |
589 |
e = e.next; |
e = e.next; |
590 |
} |
} |
591 |
return -1; |
return -1; |
592 |
} |
} |
593 |
|
|
594 |
|
/** |
595 |
|
* Returns the last index where the element is located in the list, or -1. |
596 |
|
* |
597 |
|
* @param o the element to look for |
598 |
|
* @return its position, or -1 if not found |
599 |
|
*/ |
600 |
public int lastIndexOf(Object o) |
public int lastIndexOf(Object o) |
601 |
{ |
{ |
602 |
int index = size - 1; |
int index = size - 1; |
603 |
Entry e = last; |
Entry e = last; |
604 |
while (e != null) |
while (e != null) |
605 |
{ |
{ |
606 |
if (e.data == null ? o == null : o.equals(e.data)) |
if (equals(o, e.data)) |
607 |
return index; |
return index; |
608 |
--index; |
index--; |
609 |
e = e.previous; |
e = e.previous; |
610 |
} |
} |
611 |
return -1; |
return -1; |
612 |
} |
} |
613 |
|
|
614 |
/** |
/** |
617 |
* methods. |
* methods. |
618 |
* |
* |
619 |
* @param index the index of the element to be returned by the first call to |
* @param index the index of the element to be returned by the first call to |
620 |
* next(), or size() to be initially positioned at the end of the list. |
* next(), or size() to be initially positioned at the end of the list |
621 |
* @exception IndexOutOfBoundsException if index < 0 || index > size(). |
* @throws IndexOutOfBoundsException if index < 0 || index > size() |
622 |
*/ |
*/ |
623 |
public ListIterator listIterator(int index) |
public ListIterator listIterator(int index) |
624 |
{ |
{ |
625 |
if (index < 0 || index > size) |
rangeInclusive(index); |
|
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + |
|
|
size); |
|
626 |
return new LinkedListItr(index); |
return new LinkedListItr(index); |
627 |
} |
} |
628 |
|
|
629 |
/** |
/** |
630 |
* Create a shallow copy of this LinkedList. |
* Create a shallow copy of this LinkedList (the elements are not cloned). |
631 |
|
* |
632 |
* @return an object of the same class as this object, containing the |
* @return an object of the same class as this object, containing the |
633 |
* same elements in the same order. |
* same elements in the same order |
634 |
*/ |
*/ |
635 |
public Object clone() |
public Object clone() |
636 |
{ |
{ |
637 |
LinkedList copy = null; |
LinkedList copy = null; |
638 |
try |
try |
639 |
{ |
{ |
640 |
copy = (LinkedList) super.clone(); |
copy = (LinkedList) super.clone(); |
641 |
} |
} |
642 |
catch (CloneNotSupportedException ex) |
catch (CloneNotSupportedException ex) |
643 |
{ |
{ |
646 |
copy.addAll(this); |
copy.addAll(this); |
647 |
return copy; |
return copy; |
648 |
} |
} |
649 |
|
|
650 |
|
/** |
651 |
|
* Returns an array which contains the elements of the list in order. |
652 |
|
* |
653 |
|
* @return an array containing the list elements |
654 |
|
*/ |
655 |
public Object[] toArray() |
public Object[] toArray() |
656 |
{ |
{ |
657 |
Object[] array = new Object[size]; |
Object[] array = new Object[size]; |
663 |
} |
} |
664 |
return array; |
return array; |
665 |
} |
} |
666 |
|
|
667 |
public Object[] toArray(Object[] array) |
/** |
668 |
{ |
* Returns an Array whose component type is the runtime component type of |
669 |
if (array.length < size) |
* the passed-in Array. The returned Array is populated with all of the |
670 |
array = (Object[]) Array.newInstance(array.getClass().getComponentType(), |
* elements in this LinkedList. If the passed-in Array is not large enough |
671 |
size); |
* to store all of the elements in this List, a new Array will be created |
672 |
else if (array.length > size) |
* and returned; if the passed-in Array is <i>larger</i> than the size |
673 |
array[size] = null; |
* of this List, then size() index will be set to null. |
674 |
|
* |
675 |
|
* @param a the passed-in Array |
676 |
|
* @return an array representation of this list |
677 |
|
* @throws ArrayStoreException if the runtime type of a does not allow |
678 |
|
* an element in this list |
679 |
|
* @throws NullPointerException if a is null |
680 |
|
*/ |
681 |
|
public Object[] toArray(Object[] a) |
682 |
|
{ |
683 |
|
if (a.length < size) |
684 |
|
a = (Object[]) Array.newInstance(a.getClass().getComponentType(), size); |
685 |
|
else if (a.length > size) |
686 |
|
a[size] = null; |
687 |
Entry e = first; |
Entry e = first; |
688 |
for (int i = 0; i < size; i++) |
for (int i = 0; i < size; i++) |
689 |
{ |
{ |
690 |
array[i] = e.data; |
a[i] = e.data; |
691 |
e = e.next; |
e = e.next; |
692 |
} |
} |
693 |
return array; |
return a; |
694 |
} |
} |
695 |
|
|
696 |
/** |
/** |
697 |
* Serialize an object to a stream. |
* Serializes this object to the given stream. |
698 |
* @serialdata the size of the list (int), followed by all the elements |
* |
699 |
* (Object) in proper order. |
* @param s the stream to write to |
700 |
|
* @throws IOException if the underlying stream fails |
701 |
|
* @serialData the size of the list (int), followed by all the elements |
702 |
|
* (Object) in proper order |
703 |
*/ |
*/ |
704 |
private void writeObject(ObjectOutputStream s) throws IOException |
private void writeObject(ObjectOutputStream s) throws IOException |
705 |
{ |
{ |
706 |
s.writeInt(size); |
s.writeInt(size); |
707 |
Iterator itr = iterator(); |
Entry e = first; |
708 |
for (int i = 0; i < size; i++) |
while (e != null) |
709 |
s.writeObject(itr.next()); |
{ |
710 |
|
s.writeObject(e.data); |
711 |
|
e = e.next; |
712 |
|
} |
713 |
} |
} |
714 |
|
|
715 |
/** |
/** |
716 |
* Deserialize an object from a stream. |
* Deserializes this object from the given stream. |
717 |
* @serialdata the size of the list (int), followed by all the elements |
* |
718 |
* (Object) in proper order. |
* @param s the stream to read from |
719 |
|
* @throws ClassNotFoundException if the underlying stream fails |
720 |
|
* @throws IOException if the underlying stream fails |
721 |
|
* @serialData the size of the list (int), followed by all the elements |
722 |
|
* (Object) in proper order |
723 |
*/ |
*/ |
724 |
private void readObject(ObjectInputStream s) |
private void readObject(ObjectInputStream s) |
725 |
throws IOException, ClassNotFoundException |
throws IOException, ClassNotFoundException |
726 |
{ |
{ |
727 |
int serialSize = s.readInt(); |
int i = s.readInt(); |
728 |
for (int i = 0; i < serialSize; i++) |
while (--i >= 0) |
729 |
addLastEntry(new Entry(s.readObject())); |
addLastEntry(new Entry(s.readObject())); |
730 |
} |
} |
731 |
|
|
732 |
/** A ListIterator over the list. This class keeps track of its |
/** |
733 |
|
* A ListIterator over the list. This class keeps track of its |
734 |
* position in the list and the two list entries it is between. |
* position in the list and the two list entries it is between. |
735 |
|
* |
736 |
|
* @author Original author unknown |
737 |
|
* @author Eric Blake <ebb9@email.byu.edu> |
738 |
*/ |
*/ |
739 |
class LinkedListItr implements ListIterator |
private final class LinkedListItr implements ListIterator |
740 |
{ |
{ |
741 |
int knownMod; |
/** Number of modifications we know about. */ |
742 |
Entry next; // entry that will be returned by next(). |
private int knownMod = modCount; |
743 |
Entry previous; // entry that will be returned by previous(). |
|
744 |
Entry lastReturned; // entry that will be affected by remove() or set(). |
/** Entry that will be returned by next(). */ |
745 |
int position; // index of `next'. |
private Entry next; |
746 |
|
|
747 |
|
/** Entry that will be returned by previous(). */ |
748 |
|
private Entry previous; |
749 |
|
|
750 |
|
/** Entry that will be affected by remove() or set(). */ |
751 |
|
private Entry lastReturned; |
752 |
|
|
753 |
|
/** Index of `next'. */ |
754 |
|
private int position; |
755 |
|
|
756 |
|
/** |
757 |
|
* Initialize the iterator. |
758 |
|
* |
759 |
|
* @param index the initial index |
760 |
|
*/ |
761 |
LinkedListItr(int index) |
LinkedListItr(int index) |
762 |
{ |
{ |
763 |
if (index == size) |
if (index == size) |
764 |
{ |
{ |
765 |
next = null; |
next = null; |
766 |
previous = last; |
previous = last; |
767 |
} |
} |
768 |
else |
else |
769 |
{ |
{ |
770 |
next = getEntry(index); |
next = getEntry(index); |
771 |
previous = next.previous; |
previous = next.previous; |
772 |
} |
} |
773 |
position = index; |
position = index; |
|
knownMod = modCount; |
|
774 |
} |
} |
775 |
|
|
776 |
|
/** |
777 |
|
* Checks for iterator consistency. |
778 |
|
* |
779 |
|
* @throws ConcurrentModificationException if the list was modified |
780 |
|
*/ |
781 |
private void checkMod() |
private void checkMod() |
782 |
{ |
{ |
783 |
if (knownMod != modCount) |
if (knownMod != modCount) |
784 |
throw new ConcurrentModificationException(); |
throw new ConcurrentModificationException(); |
785 |
} |
} |
786 |
|
|
787 |
|
/** |
788 |
|
* Returns the index of the next element. |
789 |
|
* |
790 |
|
* @return the next index |
791 |
|
* @throws ConcurrentModificationException if the list was modified |
792 |
|
*/ |
793 |
public int nextIndex() |
public int nextIndex() |
794 |
{ |
{ |
795 |
checkMod(); |
checkMod(); |
796 |
return position; |
return position; |
797 |
} |
} |
798 |
|
|
799 |
|
/** |
800 |
|
* Returns the index of the previous element. |
801 |
|
* |
802 |
|
* @return the previous index |
803 |
|
* @throws ConcurrentModificationException if the list was modified |
804 |
|
*/ |
805 |
public int previousIndex() |
public int previousIndex() |
806 |
{ |
{ |
807 |
checkMod(); |
checkMod(); |
808 |
return position - 1; |
return position - 1; |
809 |
} |
} |
810 |
|
|
811 |
|
/** |
812 |
|
* Returns true if more elements exist via next. |
813 |
|
* |
814 |
|
* @return true if next will succeed |
815 |
|
* @throws ConcurrentModificationException if the list was modified |
816 |
|
*/ |
817 |
public boolean hasNext() |
public boolean hasNext() |
818 |
{ |
{ |
819 |
checkMod(); |
checkMod(); |
820 |
return (next != null); |
return (next != null); |
821 |
} |
} |
822 |
|
|
823 |
|
/** |
824 |
|
* Returns true if more elements exist via previous. |
825 |
|
* |
826 |
|
* @return true if previous will succeed |
827 |
|
* @throws ConcurrentModificationException if the list was modified |
828 |
|
*/ |
829 |
public boolean hasPrevious() |
public boolean hasPrevious() |
830 |
{ |
{ |
831 |
checkMod(); |
checkMod(); |
832 |
return (previous != null); |
return (previous != null); |
833 |
} |
} |
834 |
|
|
835 |
|
/** |
836 |
|
* Returns the next element. |
837 |
|
* |
838 |
|
* @return the next element |
839 |
|
* @throws ConcurrentModificationException if the list was modified |
840 |
|
* @throws NoSuchElementException if there is no next |
841 |
|
*/ |
842 |
public Object next() |
public Object next() |
843 |
{ |
{ |
844 |
checkMod(); |
checkMod(); |
845 |
if (next == null) |
if (next == null) |
846 |
throw new NoSuchElementException(); |
throw new NoSuchElementException(); |
847 |
position++; |
position++; |
848 |
lastReturned = previous = next; |
lastReturned = previous = next; |
849 |
next = lastReturned.next; |
next = lastReturned.next; |
850 |
return lastReturned.data; |
return lastReturned.data; |
851 |
} |
} |
852 |
|
|
853 |
|
/** |
854 |
|
* Returns the previous element. |
855 |
|
* |
856 |
|
* @return the previous element |
857 |
|
* @throws ConcurrentModificationException if the list was modified |
858 |
|
* @throws NoSuchElementException if there is no previous |
859 |
|
*/ |
860 |
public Object previous() |
public Object previous() |
861 |
{ |
{ |
862 |
checkMod(); |
checkMod(); |
863 |
if (previous == null) |
if (previous == null) |
864 |
throw new NoSuchElementException(); |
throw new NoSuchElementException(); |
865 |
position--; |
position--; |
866 |
lastReturned = next = previous; |
lastReturned = next = previous; |
867 |
previous = lastReturned.previous; |
previous = lastReturned.previous; |
868 |
return lastReturned.data; |
return lastReturned.data; |
869 |
} |
} |
870 |
|
|
871 |
|
/** |
872 |
|
* Remove the most recently returned element from the list. |
873 |
|
* |
874 |
|
* @throws ConcurrentModificationException if the list was modified |
875 |
|
* @throws IllegalStateException if there was no last element |
876 |
|
*/ |
877 |
public void remove() |
public void remove() |
878 |
{ |
{ |
879 |
checkMod(); |
checkMod(); |
880 |
if (lastReturned == null) |
if (lastReturned == null) |
881 |
throw new IllegalStateException(); |
throw new IllegalStateException(); |
882 |
|
|
883 |
// Adjust the position to before the removed element, if the element |
// Adjust the position to before the removed element, if the element |
884 |
// being removed is behind the cursor. |
// being removed is behind the cursor. |
885 |
if (lastReturned == previous) |
if (lastReturned == previous) |
886 |
position--; |
position--; |
887 |
|
|
888 |
next = lastReturned.next; |
next = lastReturned.next; |
889 |
previous = lastReturned.previous; |
previous = lastReturned.previous; |
|
modCount++; |
|
|
knownMod++; |
|
890 |
removeEntry(lastReturned); |
removeEntry(lastReturned); |
891 |
|
knownMod++; |
892 |
|
|
893 |
lastReturned = null; |
lastReturned = null; |
894 |
} |
} |
895 |
|
|
896 |
|
/** |
897 |
|
* Adds an element between the previous and next, and advance to the next. |
898 |
|
* |
899 |
|
* @param o the element to add |
900 |
|
* @throws ConcurrentModificationException if the list was modified |
901 |
|
*/ |
902 |
public void add(Object o) |
public void add(Object o) |
903 |
{ |
{ |
904 |
checkMod(); |
checkMod(); |
905 |
modCount++; |
modCount++; |
906 |
knownMod++; |
knownMod++; |
907 |
|
size++; |
908 |
|
position++; |
909 |
Entry e = new Entry(o); |
Entry e = new Entry(o); |
910 |
e.previous = previous; |
e.previous = previous; |
911 |
e.next = next; |
e.next = next; |
912 |
|
|
913 |
if (previous != null) |
if (previous != null) |
914 |
previous.next = e; |
previous.next = e; |
915 |
else |
else |
916 |
first = e; |
first = e; |
917 |
|
|
918 |
if (next != null) |
if (next != null) |
919 |
{ |
{ |
920 |
next.previous = e; |
next.previous = e; |
921 |
next = next.next; |
next = next.next; |
922 |
} |
} |
923 |
else |
else |
924 |
last = e; |
last = e; |
925 |
|
|
926 |
previous = e; |
previous = e; |
|
size++; |
|
|
position++; |
|
927 |
lastReturned = null; |
lastReturned = null; |
928 |
} |
} |
929 |
|
|
930 |
|
/** |
931 |
|
* Changes the contents of the element most recently returned. |
932 |
|
* |
933 |
|
* @param o the new element |
934 |
|
* @throws ConcurrentModificationException if the list was modified |
935 |
|
* @throws IllegalStateException if there was no last element |
936 |
|
*/ |
937 |
public void set(Object o) |
public void set(Object o) |
938 |
{ |
{ |
939 |
checkMod(); |
checkMod(); |
940 |
if (lastReturned == null) |
if (lastReturned == null) |
941 |
throw new IllegalStateException(); |
throw new IllegalStateException(); |
942 |
lastReturned.data = o; |
lastReturned.data = o; |
943 |
} |
} |
944 |
} // class LinkedListItr |
} // class LinkedListItr |
945 |
} |
} |