1 /* LinkedList.java -- Linked list implementation of the List interface
2 Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 As a special exception, if you link this library with other files to
22 produce an executable, this library does not by itself cause the
23 resulting executable to be covered by the GNU General Public License.
24 This exception does not however invalidate any other reasons why the
25 executable file might be covered by the GNU General Public License. */
29 import java.io.Serializable;
30 import java.io.ObjectOutputStream;
31 import java.io.ObjectInputStream;
32 import java.io.IOException;
33 import java.lang.reflect.Array;
36 * 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>
42 * LinkedList is not synchronized, so if you need multi-threaded access,
44 * <code>List l = Collections.synchronizedList(new LinkedList(...));</code>
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.
53 * @author Original author unknown
54 * @author Bryce McKinlay
55 * @author Eric Blake <ebb9@email.byu.edu>
59 * @see Collections#synchronizedList(List)
61 * @status missing javadoc, but complete to 1.4
63 public class LinkedList extends AbstractSequentialList
64 implements List, Cloneable, Serializable
67 * Compatible with JDK 1.2.
69 private static final long serialVersionUID = 876323262645176354L;
72 * The first element in the list.
74 transient Entry first;
77 * The last element in the list.
82 * The current length of the list.
84 transient int size = 0;
87 * Class to represent an entry in the list. Holds a single element.
89 private static final class Entry
91 /** The element in the list. */
94 /** The next list entry, null if this is last. */
97 /** The previous list entry, null if this is first. */
101 * Construct an entry.
102 * @param data the list element
111 * Obtain the Entry at a given position in a list. This method of course
112 * takes linear time, but it is intelligent enough to take the shorter of the
113 * paths to get to the Entry required. This implies that the first or last
114 * entry in the list is obtained in constant time, which is a very desirable
116 * For speed and flexibility, range checking is not done in this method:
117 * Incorrect values will be returned if (n < 0) or (n >= size).
119 * @param n the number of the entry to get
120 * @return the entry at position n
122 private Entry getEntry(int n)
128 // n less than size/2, iterate from start
135 // n greater than size/2, iterate from end
143 * Remove an entry from the list. This will adjust size and deal with
144 * `first' and `last' appropriatly.
146 * @param e the entry to remove
148 private void removeEntry(Entry e)
159 e.next.previous = null;
164 e.previous.next = null;
168 e.next.previous = e.previous;
169 e.previous.next = e.next;
175 * Checks that the index is in the range of possible elements (inclusive).
177 * @param index the index to check
178 * @throws IndexOutOfBoundsException if index < 0 || index > size
180 private void checkBoundsInclusive(int index)
182 if (index < 0 || index > size)
183 throw new IndexOutOfBoundsException("Index: " + index + ", Size:"
188 * Checks that the index is in the range of existing elements (exclusive).
190 * @param index the index to check
191 * @throws IndexOutOfBoundsException if index < 0 || index >= size
193 private void checkBoundsExclusive(int index)
195 if (index < 0 || index >= size)
196 throw new IndexOutOfBoundsException("Index: " + index + ", Size:"
201 * Create an empty linked list.
208 * Create a linked list containing the elements, in order, of a given
211 * @param c the collection to populate this list from
212 * @throws NullPointerException if c is null
214 public LinkedList(Collection c)
220 * Returns the first element in the list.
222 * @return the first list element
223 * @throws NoSuchElementException if the list is empty
225 public Object getFirst()
228 throw new NoSuchElementException();
233 * Returns the last element in the list.
235 * @return the last list element
236 * @throws NoSuchElementException if the list is empty
238 public Object getLast()
241 throw new NoSuchElementException();
246 * Remove and return the first element in the list.
248 * @return the former first element in the list
249 * @throws NoSuchElementException if the list is empty
251 public Object removeFirst()
254 throw new NoSuchElementException();
257 Object r = first.data;
259 if (first.next != null)
260 first.next.previous = null;
270 * Remove and return the last element in the list.
272 * @return the former last element in the list
273 * @throws NoSuchElementException if the list is empty
275 public Object removeLast()
278 throw new NoSuchElementException();
281 Object r = last.data;
283 if (last.previous != null)
284 last.previous.next = null;
288 last = last.previous;
294 * Insert an element at the first of the list.
296 * @param o the element to insert
298 public void addFirst(Object o)
300 Entry e = new Entry(o);
315 * Insert an element at the last of the list.
317 * @param o the element to insert
319 public void addLast(Object o)
321 addLastEntry(new Entry(o));
325 * Inserts an element at the end of the list.
327 * @param e the entry to add
329 private void addLastEntry(Entry e)
344 * Returns true if the list contains the given object. Comparison is done by
345 * <code>o == null ? e = null : o.equals(e)</code>.
347 * @param o the element to look for
348 * @return true if it is found
350 public boolean contains(Object o)
355 if (equals(o, e.data))
363 * Returns the size of the list.
365 * @return the list size
373 * Adds an element to the end of the list.
375 * @param e the entry to add
376 * @return true, as it always succeeds
378 public boolean add(Object o)
380 addLastEntry(new Entry(o));
385 * Removes the entry at the lowest index in the list that matches the given
386 * object, comparing by <code>o == null ? e = null : o.equals(e)</code>.
388 * @param o the object to remove
389 * @return true if an instance of the object was removed
391 public boolean remove(Object o)
396 if (equals(o, e.data))
407 * Append the elements of the collection in iteration order to the end of
408 * this list. If this list is modified externally (for example, if this
409 * list is the collection), behavior is unspecified.
411 * @param c the collection to append
412 * @return true if the list was modified
413 * @throws NullPointerException if c is null
415 public boolean addAll(Collection c)
417 return addAll(size, c);
421 * Insert the elements of the collection in iteration order at the given
422 * index of this list. If this list is modified externally (for example,
423 * if this list is the collection), behavior is unspecified.
425 * @param c the collection to append
426 * @return true if the list was modified
427 * @throws NullPointerException if c is null
428 * @throws IndexOutOfBoundsException if index < 0 || index > size()
430 public boolean addAll(int index, Collection c)
432 checkBoundsInclusive(index);
433 int csize = c.size();
438 Iterator itr = c.iterator();
440 // Get the entries just before and after index. If index is at the start
441 // of the list, BEFORE is null. If index is at the end of the list, AFTER
442 // is null. If the list is empty, both are null.
447 after = getEntry(index);
448 before = after.previous;
453 // Create the first new entry. We do not yet set the link from `before'
454 // to the first entry, in order to deal with the case where (c == this).
455 // [Actually, we don't have to handle this case to fufill the
456 // contract for addAll(), but Sun's implementation appears to.]
457 Entry e = new Entry(itr.next());
462 // Create and link all the remaining entries.
463 for (int pos = 1; pos < csize; pos++)
465 e = new Entry(itr.next());
471 // Link the new chain of entries into the list.
481 before.next = firstNew;
488 * Remove all elements from this list.
502 * Return the element at index.
504 * @param index the place to look
505 * @return the element at index
506 * @throws IndexOutOfBoundsException if index < 0 || index >= size()
508 public Object get(int index)
510 checkBoundsExclusive(index);
511 return getEntry(index).data;
515 * Replace the element at the given location in the list.
517 * @param index which index to change
518 * @param o the new element
519 * @return the prior element
520 * @throws IndexOutOfBoundsException if index < 0 || index >= size()
522 public Object set(int index, Object o)
524 checkBoundsExclusive(index);
525 Entry e = getEntry(index);
532 * Inserts an element in the given position in the list.
534 * @param index where to insert the element
535 * @param o the element to insert
536 * @throws IndexOutOfBoundsException if index < 0 || index > size()
538 public void add(int index, Object o)
540 checkBoundsInclusive(index);
541 Entry e = new Entry(o);
546 Entry after = getEntry(index);
548 e.previous = after.previous;
549 if (after.previous == null)
552 after.previous.next = e;
561 * Removes the element at the given position from the list.
563 * @param index the location of the element to remove
564 * @return the removed element
565 * @throws IndexOutOfBoundsException if index < 0 || index > size()
567 public Object remove(int index)
569 checkBoundsExclusive(index);
570 Entry e = getEntry(index);
576 * Returns the first index where the element is located in the list, or -1.
578 * @param o the element to look for
579 * @return its position, or -1 if not found
581 public int indexOf(Object o)
587 if (equals(o, e.data))
596 * Returns the last index where the element is located in the list, or -1.
598 * @param o the element to look for
599 * @return its position, or -1 if not found
601 public int lastIndexOf(Object o)
603 int index = size - 1;
607 if (equals(o, e.data))
616 * Obtain a ListIterator over this list, starting at a given index. The
617 * ListIterator returned by this method supports the add, remove and set
620 * @param index the index of the element to be returned by the first call to
621 * next(), or size() to be initially positioned at the end of the list
622 * @throws IndexOutOfBoundsException if index < 0 || index > size()
624 public ListIterator listIterator(int index)
626 checkBoundsInclusive(index);
627 return new LinkedListItr(index);
631 * Create a shallow copy of this LinkedList (the elements are not cloned).
633 * @return an object of the same class as this object, containing the
634 * same elements in the same order
636 public Object clone()
638 LinkedList copy = null;
641 copy = (LinkedList) super.clone();
643 catch (CloneNotSupportedException ex)
652 * Returns an array which contains the elements of the list in order.
654 * @return an array containing the list elements
656 public Object[] toArray()
658 Object[] array = new Object[size];
660 for (int i = 0; i < size; i++)
669 * Returns an Array whose component type is the runtime component type of
670 * the passed-in Array. The returned Array is populated with all of the
671 * elements in this LinkedList. If the passed-in Array is not large enough
672 * to store all of the elements in this List, a new Array will be created
673 * and returned; if the passed-in Array is <i>larger</i> than the size
674 * of this List, then size() index will be set to null.
676 * @param a the passed-in Array
677 * @return an array representation of this list
678 * @throws ArrayStoreException if the runtime type of a does not allow
679 * an element in this list
680 * @throws NullPointerException if a is null
682 public Object[] toArray(Object[] a)
685 a = (Object[]) Array.newInstance(a.getClass().getComponentType(), size);
686 else if (a.length > size)
689 for (int i = 0; i < size; i++)
698 * Serializes this object to the given stream.
700 * @param s the stream to write to
701 * @throws IOException if the underlying stream fails
702 * @serialData the size of the list (int), followed by all the elements
703 * (Object) in proper order
705 private void writeObject(ObjectOutputStream s) throws IOException
707 s.defaultWriteObject();
712 s.writeObject(e.data);
718 * Deserializes this object from the given stream.
720 * @param s the stream to read from
721 * @throws ClassNotFoundException if the underlying stream fails
722 * @throws IOException if the underlying stream fails
723 * @serialData the size of the list (int), followed by all the elements
724 * (Object) in proper order
726 private void readObject(ObjectInputStream s)
727 throws IOException, ClassNotFoundException
729 s.defaultReadObject();
732 addLastEntry(new Entry(s.readObject()));
736 * A ListIterator over the list. This class keeps track of its
737 * position in the list and the two list entries it is between.
739 * @author Original author unknown
740 * @author Eric Blake <ebb9@email.byu.edu>
742 private final class LinkedListItr implements ListIterator
744 /** Number of modifications we know about. */
745 private int knownMod = modCount;
747 /** Entry that will be returned by next(). */
750 /** Entry that will be returned by previous(). */
751 private Entry previous;
753 /** Entry that will be affected by remove() or set(). */
754 private Entry lastReturned;
756 /** Index of `next'. */
757 private int position;
760 * Initialize the iterator.
762 * @param index the initial index
764 LinkedListItr(int index)
773 next = getEntry(index);
774 previous = next.previous;
780 * Checks for iterator consistency.
782 * @throws ConcurrentModificationException if the list was modified
784 private void checkMod()
786 if (knownMod != modCount)
787 throw new ConcurrentModificationException();
791 * Returns the index of the next element.
793 * @return the next index
794 * @throws ConcurrentModificationException if the list was modified
796 public int nextIndex()
803 * Returns the index of the previous element.
805 * @return the previous index
806 * @throws ConcurrentModificationException if the list was modified
808 public int previousIndex()
815 * Returns true if more elements exist via next.
817 * @return true if next will succeed
818 * @throws ConcurrentModificationException if the list was modified
820 public boolean hasNext()
823 return (next != null);
827 * Returns true if more elements exist via previous.
829 * @return true if previous will succeed
830 * @throws ConcurrentModificationException if the list was modified
832 public boolean hasPrevious()
835 return (previous != null);
839 * Returns the next element.
841 * @return the next element
842 * @throws ConcurrentModificationException if the list was modified
843 * @throws NoSuchElementException if there is no next
849 throw new NoSuchElementException();
851 lastReturned = previous = next;
852 next = lastReturned.next;
853 return lastReturned.data;
857 * Returns the previous element.
859 * @return the previous element
860 * @throws ConcurrentModificationException if the list was modified
861 * @throws NoSuchElementException if there is no previous
863 public Object previous()
866 if (previous == null)
867 throw new NoSuchElementException();
869 lastReturned = next = previous;
870 previous = lastReturned.previous;
871 return lastReturned.data;
875 * Remove the most recently returned element from the list.
877 * @throws ConcurrentModificationException if the list was modified
878 * @throws IllegalStateException if there was no last element
883 if (lastReturned == null)
884 throw new IllegalStateException();
886 // Adjust the position to before the removed element, if the element
887 // being removed is behind the cursor.
888 if (lastReturned == previous)
891 next = lastReturned.next;
892 previous = lastReturned.previous;
893 removeEntry(lastReturned);
900 * Adds an element between the previous and next, and advance to the next.
902 * @param o the element to add
903 * @throws ConcurrentModificationException if the list was modified
905 public void add(Object o)
912 Entry e = new Entry(o);
913 e.previous = previous;
916 if (previous != null)
931 * Changes the contents of the element most recently returned.
933 * @param o the new element
934 * @throws ConcurrentModificationException if the list was modified
935 * @throws IllegalStateException if there was no last element
937 public void set(Object o)
940 if (lastReturned == null)
941 throw new IllegalStateException();
942 lastReturned.data = o;
944 } // class LinkedListItr