【源代码】java.util.LinkedList

java.util.LinkedList是一个基于双向链表的容器类型。这里将罗列出其具体实现并分析其原理。

类声明:

public class LinkedList extends AbstractSequentialList


实现接口:

implements List, Deque, Cloneable, Serializable


成员变量为:

private static final long serialVersionUID = 876323262645176354L;
transient Entry first;
transient Entry last;
transient int size = 0;

成员变量中定义了序列化ID,首节点first,尾节点last和容器当前大小size,size为容器中当前元素的个数。

其中有两点需要注意:

(一)首节点,尾节点和大小不作为序列化成员,声明为transient变量。

(二)其中Entry为一个泛型容器类,是链表节点的类型,其声明为LinkedList的静态内部类,定义如下:

 private static final class Entry   {
     T data; 
     
     Entry next;
 
     Entry previous;

     Entry(T data)
     {
       this.data = data;
     }
}

Entry类型结构清晰,是一个标志性的双向链表。包含前驱和后继的引用。构造函数用于初始化值。


LinkedList中定义了针对节点对象的获取,移除函数,定义如下:

136:   Entry getEntry(int n)
 137:   {
 138:     Entry e;
 139:     if (n < size / 2)
 140:       {
 141:         e = first;
 142:         // n less than size/2, iterate from start
 143:         while (n-- > 0)
 144:           e = e.next;
 145:       }
 146:     else
 147:       {
 148:         e = last;
 149:         // n greater than size/2, iterate from end
 150:         while (++n < size)
 151:           e = e.previous;
 152:       }
 153:     return e;
 154:   }
163:   void removeEntry(Entry e)
 164:   {
 165:     modCount++;
 166:     size--;
 167:     if (size == 0)
 168:       first = last = null;
 169:     else
 170:       {
 171:         if (e == first)
 172:           {
 173:             first = e.next;
 174:             e.next.previous = null;
 175:           }
 176:         else if (e == last)
 177:           {
 178:             last = e.previous;
 179:             e.previous.next = null;
 180:           }
 181:         else
 182:           {
 183:             e.next.previous = e.previous;
 184:             e.previous.next = e.next;
 185:           }
 186:       }
 187:   }

这里需要留意,对链表进行修改的操作中都有一个ModCount的变量在自增,它是Modification Count的意思,是一个记录链表修改次数的计数器。它的作用是帮助检测链表被修改的情况。


然后定义了检查索引边界的两个私有方法,一个检测索引是否在可行范围内,一个检测索引是否在可行范围外

 195:   private void checkBoundsInclusive(int index)
 196:   {
 197:     if (index < 0 || index > size)
 198:       throw new IndexOutOfBoundsException("Index: " + index + ", Size:"
 199:                                           + size);
 200:   }
 208:   private void checkBoundsExclusive(int index)
 209:   {
 210:     if (index < 0 || index >= size)
 211:       throw new IndexOutOfBoundsException("Index: " + index + ", Size:"
 212:                                           + size);
 213:   }


接下来,LinkedList中定义了两个构造函数。分别针对无参情况和参数为一个容器类型的情况。

218:   public LinkedList()
 219:   {
 220:   }
229:   public LinkedList(Collection c)
 230:   {
 231:     addAll(c);
 232:   }
其中,addAll有两个定义,参数为容器类型定义如下:

 430:   public boolean addAll(Collection c)
 431:   {
 432:     return addAll(size, c);
 433:   }
另一个为:

445:   public boolean addAll(int index, Collection c)
 446:   {
 447:     checkBoundsInclusive(index);
 448:     int csize = c.size();
 449: 
 450:     if (csize == 0)
 451:       return false;
 452: 
 453:     Iterator itr = c.iterator();
 454: 
 455:     // Get the entries just before and after index. If index is at the start
 456:     // of the list, BEFORE is null. If index is at the end of the list, AFTER
 457:     // is null. If the list is empty, both are null.
 458:     Entry after = null;
 459:     Entry before = null;
 460:     if (index != size)
 461:       {
 462:         after = getEntry(index);
 463:         before = after.previous;
 464:       }
 465:     else
 466:       before = last;
 467: 
 468:     // Create the first new entry. We do not yet set the link from `before'
 469:     // to the first entry, in order to deal with the case where (c == this).
 470:     // [Actually, we don't have to handle this case to fufill the
 471:     // contract for addAll(), but Sun's implementation appears to.]
 472:     Entry e = new Entry(itr.next());
 473:     e.previous = before;
 474:     Entry prev = e;
 475:     Entry firstNew = e;
 476: 
 477:     // Create and link all the remaining entries.
 478:     for (int pos = 1; pos < csize; pos++)
 479:       {
 480:         e = new Entry(itr.next());
 481:         e.previous = prev;
 482:         prev.next = e;
 483:         prev = e;
 484:       }
 485: 
 486:     // Link the new chain of entries into the list.
 487:     modCount++;
 488:     size += csize;
 489:     prev.next = after;
 490:     if (after != null)
 491:       after.previous = e;
 492:     else
 493:       last = e;
 494: 
 495:     if (before != null)
 496:       before.next = firstNew;
 497:     else
 498:       first = firstNew;
 499:     return true;
 500:   }
如上方法对容器使用迭代器进行遍历,逐一将对象复制拷贝到当前链表中。


然后类型还定义了针对首尾节点的单独操作,获取,添加和删除操作,定义如下:

 240:   public T getFirst()
 241:   {
 242:     if (size == 0)
 243:       throw new NoSuchElementException();
 244:     return first.data;
 245:   }

 253:   public T getLast()
 254:   {
 255:     if (size == 0)
 256:       throw new NoSuchElementException();
 257:     return last.data;
 258:   }

 266:   public T removeFirst()
 267:   {
 268:     if (size == 0)
 269:       throw new NoSuchElementException();
 270:     modCount++;
 271:     size--;
 272:     T r = first.data;
 273: 
 274:     if (first.next != null)
 275:       first.next.previous = null;
 276:     else
 277:       last = null;
 278: 
 279:     first = first.next;
 280: 
 281:     return r;
 282:   }
 283: 
 290:   public T removeLast()
 291:   {
 292:     if (size == 0)
 293:       throw new NoSuchElementException();
 294:     modCount++;
 295:     size--;
 296:     T r = last.data;
 297: 
 298:     if (last.previous != null)
 299:       last.previous.next = null;
 300:     else
 301:       first = null;
 302: 
 303:     last = last.previous;
 304: 
 305:     return r;
 306:   }

 313:   public void addFirst(T o)
 314:   {
 315:     Entry e = new Entry(o);
 316: 
 317:     modCount++;
 318:     if (size == 0)
 319:       first = last = e;
 320:     else
 321:       {
 322:         e.next = first;
 323:         first.previous = e;
 324:         first = e;
 325:       }
 326:     size++;
 327:   }

 334:   public void addLast(T o)
 335:   {
 336:     addLastEntry(new Entry(o));
 337:   }
其中addLastEntry方法定义如下:

 344:   private void addLastEntry(Entry e)
 345:   {
 346:     modCount++;
 347:     if (size == 0)
 348:       first = last = e;
 349:     else
 350:       {
 351:         e.previous = last;
 352:         last.next = e;
 353:         last = e;
 354:       }
 355:     size++;
 356:   }
这里之所以单独将addLastEntry()方法提出来定义是因为链表的新元素默认在尾部添加,并且在添加元素的方法boolean add(T o)中再次使用了addLastEntry()方法:

393:   public boolean add(T o)
 394:   {
 395:     addLastEntry(new Entry(o));
 396:     return true;
 397:   }
同时LinkedList还支持插入元素功能,可以指定一个索引作为插入位置,方法名同样为add,但是无返回值,参数为int index和T o:

 553:   public void add(int index, T o)
 554:   {
 555:     checkBoundsInclusive(index);
 556:     Entry e = new Entry(o);
 557: 
 558:     if (index < size)
 559:       {
 560:         modCount++;
 561:         Entry after = getEntry(index);
 562:         e.next = after;
 563:         e.previous = after.previous;
 564:         if (after.previous == null)
 565:           first = e;
 566:         else
 567:           after.previous.next = e;
 568:         after.previous = e;
 569:         size++;
 570:       }
 571:     else
 572:       addLastEntry(e);
 573:   }
很有意思的是,还有一个方法叫offer(T value)定义如下:

 719:   public boolean offer(T value)
 720:   {
 721:     return add(value);
 722:   }
它和add(T o)有什么不同呢?


该容器中还有三个返回首元素的方法,但是对于容器为空时,它们的返回值有所不同:

732:   public T element()
 733:   {
 734:     return getFirst();
 735:   }
element()方法返回首节点,但不删除首节点。如果链表为空,抛出NoSuchElementException。


745:   public T peek()
 746:   {
 747:     if (size == 0)
 748:       return null;
 749:     return getFirst();
 750:   }
peek()方法,返回首节点,但不删除它。如果链表为空,返回null。


 759:   public T poll()
 760:   {
 761:     if (size == 0)
 762:       return null;
 763:     return removeFirst();
 764:   }
poll()方法返回首节点,但删除首节点,如果链表为空,返回null。

接下来,容器中定义了两个序列化方法。分别为写入和读取数据流。

当容器序列化时,成员函数writeObject将会把链表作为数据顺序写入输出流,定义如下:

 786:   private void writeObject(ObjectOutputStream s) throws IOException
 787:   {
 788:     s.defaultWriteObject();
 789:     s.writeInt(size);
 790:     Entry e = first;
 791:     while (e != null)
 792:       {
 793:         s.writeObject(e.data);
 794:         e = e.next;
 795:       }
 796:   }
如下为从输入流中读入链表的方法:

 807:   private void readObject(ObjectInputStream s)
 808:     throws IOException, ClassNotFoundException
 809:   {
 810:     s.defaultReadObject();
 811:     int i = s.readInt();
 812:     while (--i >= 0)
 813:       addLastEntry(new Entry((T) s.readObject()));
 814:   }

在LinkedList结尾,定义了一个非常重要的内部类,迭代器Iterator。

类声明:

private final class LinkedListItr
实现接口:

implements ListIterator
成员变量:

 827:     private int knownMod = modCount;

 830:     private Entry next;

 833:     private Entry previous;

 836:     private Entry lastReturned;

 839:     private int position;
其中定义了构造方法:

LinkedListItr(int index)
 847:     {
 848:       if (index == size)
 849:         {
 850:           next = null;
 851:           previous = (Entry) last;
 852:         }
 853:       else
 854:         {
 855:           next = (Entry) getEntry(index);
 856:           previous = next.previous;
 857:         }
 858:       position = index;
 859:     }
迭代器中有一个方法值得注意:

 866:     private void checkMod()
 867:     {
 868:       if (knownMod != modCount)
 869:         throw new ConcurrentModificationException();
 870:     }
这是检测链表是否被修改的方法,用于在多线程和迭代过程中监测链表的情况。


然后就是我们常用的hasNext()和next()方法:

 897:     public boolean hasNext()
 898:     {
 899:       return (next != null);
 900:     }
 919:     public I next()
 920:     {
 921:       checkMod();
 922:       if (next == null)
 923:         throw new NoSuchElementException();
 924:       position++;
 925:       lastReturned = previous = next;
 926:       next = lastReturned.next;
 927:       return lastReturned.data;
 928:     }
迭代器还提供了移除和添加元素的方法:

 954:     public void remove()
 955:     {
 956:       checkMod();
 957:       if (lastReturned == null)
 958:         throw new IllegalStateException();
 959: 
 960:       // Adjust the position to before the removed element, if the element
 961:       // being removed is behind the cursor.
 962:       if (lastReturned == previous)
 963:         position--;
 964: 
 965:       next = lastReturned.next;
 966:       previous = lastReturned.previous;
 967:       removeEntry((Entry) lastReturned);
 968:       knownMod++;
 969: 
 970:       lastReturned = null;
 971:     }
 979:     public void add(I o)
 980:     {
 981:       checkMod();
 982:       modCount++;
 983:       knownMod++;
 984:       size++;
 985:       position++;
 986:       Entry e = new Entry(o);
 987:       e.previous = previous;
 988:       e.next = next;
 989: 
 990:       if (previous != null)
 991:         previous.next = e;
 992:       else
 993:         first = (Entry) e;
 994: 
 995:       if (next != null)
 996:         next.previous = e;
 997:       else
 998:         last = (Entry) e;
 999: 
1000:       previous = e;
1001:       lastReturned = null;
1002:     }

如果希望从后往前遍历链表,LinkedList还提供了倒序迭代器:

类定义如下:

public Iterator descendingIterator()
其成员函数与之前类似,这里省去,可以参考文后提供的源代码。


最后还有两个LinkedList的成员函数比较有意思:

1231:   public boolean removeFirstOccurrence(Object o)
1232:   {
1233:     return remove(o);
1234:   }
1245:   public boolean removeLastOccurrence(Object o)
1246:   {
1247:     Entry e = last;
1248:     while (e != null)
1249:       {
1250:     if (equals(o, e.data))
1251:       {
1252:         removeEntry(e);
1253:         return true;
1254:       }
1255:     e = e.previous;
1256:       }
1257:     return false;
1258:   }
这是两个删除元素的方法,类似于remove(),其定义如下:

 406:   public boolean remove(Object o)
 407:   {
 408:     Entry e = first;
 409:     while (e != null)
 410:       {
 411:         if (equals(o, e.data))
 412:           {
 413:             removeEntry(e);
 414:             return true;
 415:           }
 416:         e = e.next;
 417:       }
 418:     return false;
 419:   }
可以发现,removeFirstOccurrence()就是remove(),是从低索引开始,移除第一个匹配的元素。但是removeLastOccurrence()则是从高索引开始,依序向前,移除第一个匹配的值。一个从前往后,一个从后往前。


本文省略了一些成员方法的介绍,大家可以通过后边的源代码自行了解。

这是我读源代码的第一篇文章,必定有出入,我将在以后不断更新文章的内容。


源代码一览

源代码来源:http://developer.classpath.org/doc/java/util/LinkedList-source.html

1: /* LinkedList.java -- Linked list implementation of the List interface
   2:    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   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)
   9: any later version.
  10: 
  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.
  15: 
  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., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package java.util;
  40: import java.io.IOException;
  41: import java.io.ObjectInputStream;
  42: import java.io.ObjectOutputStream;
  43: import java.io.Serializable;
  44: import java.lang.reflect.Array;
  45: 
  46: /**
  47:  * Linked list implementation of the List interface. In addition to the
  48:  * methods of the List interface, this class provides access to the first
  49:  * and last list elements in O(1) time for easy stack, queue, or double-ended
  50:  * queue (deque) creation. The list is doubly-linked, with traversal to a
  51:  * given index starting from the end closest to the element.

52: * 53: * LinkedList is not synchronized, so if you need multi-threaded access, 54: * consider using:
55: * List l = Collections.synchronizedList(new LinkedList(...)); 56: *

57: * 58: * The iterators are fail-fast, meaning that any structural 59: * modification, except for remove() called on the iterator 60: * itself, cause the iterator to throw a 61: * {@link ConcurrentModificationException} rather than exhibit 62: * non-deterministic behavior. 63: * 64: * @author Original author unknown 65: * @author Bryce McKinlay 66: * @author Eric Blake ([email protected]) 67: * @author Tom Tromey ([email protected]) 68: * @author Andrew John Hughes ([email protected]) 69: * @see List 70: * @see ArrayList 71: * @see Vector 72: * @see Collections#synchronizedList(List) 73: * @since 1.2 74: * @status Complete to 1.6 75: */ 76: public class LinkedList extends AbstractSequentialList 77: implements List, Deque, Cloneable, Serializable 78: { 79: /** 80: * Compatible with JDK 1.2. 81: */ 82: private static final long serialVersionUID = 876323262645176354L; 83: 84: /** 85: * The first element in the list. 86: */ 87: transient Entry first; 88: 89: /** 90: * The last element in the list. 91: */ 92: transient Entry last; 93: 94: /** 95: * The current length of the list. 96: */ 97: transient int size = 0; 98: 99: /** 100: * Class to represent an entry in the list. Holds a single element. 101: */ 102: private static final class Entry 103: { 104: /** The element in the list. */ 105: T data; 106: 107: /** The next list entry, null if this is last. */ 108: Entry next; 109: 110: /** The previous list entry, null if this is first. */ 111: Entry previous; 112: 113: /** 114: * Construct an entry. 115: * @param data the list element 116: */ 117: Entry(T data) 118: { 119: this.data = data; 120: } 121: } // class Entry 122: 123: /** 124: * Obtain the Entry at a given position in a list. This method of course 125: * takes linear time, but it is intelligent enough to take the shorter of the 126: * paths to get to the Entry required. This implies that the first or last 127: * entry in the list is obtained in constant time, which is a very desirable 128: * property. 129: * For speed and flexibility, range checking is not done in this method: 130: * Incorrect values will be returned if (n < 0) or (n >= size). 131: * 132: * @param n the number of the entry to get 133: * @return the entry at position n 134: */ 135: // Package visible for use in nested classes. 136: Entry getEntry(int n) 137: { 138: Entry e; 139: if (n < size / 2) 140: { 141: e = first; 142: // n less than size/2, iterate from start 143: while (n-- > 0) 144: e = e.next; 145: } 146: else 147: { 148: e = last; 149: // n greater than size/2, iterate from end 150: while (++n < size) 151: e = e.previous; 152: } 153: return e; 154: } 155: 156: /** 157: * Remove an entry from the list. This will adjust size and deal with 158: * `first' and `last' appropriatly. 159: * 160: * @param e the entry to remove 161: */ 162: // Package visible for use in nested classes. 163: void removeEntry(Entry e) 164: { 165: modCount++; 166: size--; 167: if (size == 0) 168: first = last = null; 169: else 170: { 171: if (e == first) 172: { 173: first = e.next; 174: e.next.previous = null; 175: } 176: else if (e == last) 177: { 178: last = e.previous; 179: e.previous.next = null; 180: } 181: else 182: { 183: e.next.previous = e.previous; 184: e.previous.next = e.next; 185: } 186: } 187: } 188: 189: /** 190: * Checks that the index is in the range of possible elements (inclusive). 191: * 192: * @param index the index to check 193: * @throws IndexOutOfBoundsException if index < 0 || index > size 194: */ 195: private void checkBoundsInclusive(int index) 196: { 197: if (index < 0 || index > size) 198: throw new IndexOutOfBoundsException("Index: " + index + ", Size:" 199: + size); 200: } 201: 202: /** 203: * Checks that the index is in the range of existing elements (exclusive). 204: * 205: * @param index the index to check 206: * @throws IndexOutOfBoundsException if index < 0 || index >= size 207: */ 208: private void checkBoundsExclusive(int index) 209: { 210: if (index < 0 || index >= size) 211: throw new IndexOutOfBoundsException("Index: " + index + ", Size:" 212: + size); 213: } 214: 215: /** 216: * Create an empty linked list. 217: */ 218: public LinkedList() 219: { 220: } 221: 222: /** 223: * Create a linked list containing the elements, in order, of a given 224: * collection. 225: * 226: * @param c the collection to populate this list from 227: * @throws NullPointerException if c is null 228: */ 229: public LinkedList(Collection c) 230: { 231: addAll(c); 232: } 233: 234: /** 235: * Returns the first element in the list. 236: * 237: * @return the first list element 238: * @throws NoSuchElementException if the list is empty 239: */ 240: public T getFirst() 241: { 242: if (size == 0) 243: throw new NoSuchElementException(); 244: return first.data; 245: } 246: 247: /** 248: * Returns the last element in the list. 249: * 250: * @return the last list element 251: * @throws NoSuchElementException if the list is empty 252: */ 253: public T getLast() 254: { 255: if (size == 0) 256: throw new NoSuchElementException(); 257: return last.data; 258: } 259: 260: /** 261: * Remove and return the first element in the list. 262: * 263: * @return the former first element in the list 264: * @throws NoSuchElementException if the list is empty 265: */ 266: public T removeFirst() 267: { 268: if (size == 0) 269: throw new NoSuchElementException(); 270: modCount++; 271: size--; 272: T r = first.data; 273: 274: if (first.next != null) 275: first.next.previous = null; 276: else 277: last = null; 278: 279: first = first.next; 280: 281: return r; 282: } 283: 284: /** 285: * Remove and return the last element in the list. 286: * 287: * @return the former last element in the list 288: * @throws NoSuchElementException if the list is empty 289: */ 290: public T removeLast() 291: { 292: if (size == 0) 293: throw new NoSuchElementException(); 294: modCount++; 295: size--; 296: T r = last.data; 297: 298: if (last.previous != null) 299: last.previous.next = null; 300: else 301: first = null; 302: 303: last = last.previous; 304: 305: return r; 306: } 307: 308: /** 309: * Insert an element at the first of the list. 310: * 311: * @param o the element to insert 312: */ 313: public void addFirst(T o) 314: { 315: Entry e = new Entry(o); 316: 317: modCount++; 318: if (size == 0) 319: first = last = e; 320: else 321: { 322: e.next = first; 323: first.previous = e; 324: first = e; 325: } 326: size++; 327: } 328: 329: /** 330: * Insert an element at the last of the list. 331: * 332: * @param o the element to insert 333: */ 334: public void addLast(T o) 335: { 336: addLastEntry(new Entry(o)); 337: } 338: 339: /** 340: * Inserts an element at the end of the list. 341: * 342: * @param e the entry to add 343: */ 344: private void addLastEntry(Entry e) 345: { 346: modCount++; 347: if (size == 0) 348: first = last = e; 349: else 350: { 351: e.previous = last; 352: last.next = e; 353: last = e; 354: } 355: size++; 356: } 357: 358: /** 359: * Returns true if the list contains the given object. Comparison is done by 360: * o == null ? e = null : o.equals(e). 361: * 362: * @param o the element to look for 363: * @return true if it is found 364: */ 365: public boolean contains(Object o) 366: { 367: Entry e = first; 368: while (e != null) 369: { 370: if (equals(o, e.data)) 371: return true; 372: e = e.next; 373: } 374: return false; 375: } 376: 377: /** 378: * Returns the size of the list. 379: * 380: * @return the list size 381: */ 382: public int size() 383: { 384: return size; 385: } 386: 387: /** 388: * Adds an element to the end of the list. 389: * 390: * @param o the entry to add 391: * @return true, as it always succeeds 392: */ 393: public boolean add(T o) 394: { 395: addLastEntry(new Entry(o)); 396: return true; 397: } 398: 399: /** 400: * Removes the entry at the lowest index in the list that matches the given 401: * object, comparing by o == null ? e = null : o.equals(e). 402: * 403: * @param o the object to remove 404: * @return true if an instance of the object was removed 405: */ 406: public boolean remove(Object o) 407: { 408: Entry e = first; 409: while (e != null) 410: { 411: if (equals(o, e.data)) 412: { 413: removeEntry(e); 414: return true; 415: } 416: e = e.next; 417: } 418: return false; 419: } 420: 421: /** 422: * Append the elements of the collection in iteration order to the end of 423: * this list. If this list is modified externally (for example, if this 424: * list is the collection), behavior is unspecified. 425: * 426: * @param c the collection to append 427: * @return true if the list was modified 428: * @throws NullPointerException if c is null 429: */ 430: public boolean addAll(Collection c) 431: { 432: return addAll(size, c); 433: } 434: 435: /** 436: * Insert the elements of the collection in iteration order at the given 437: * index of this list. If this list is modified externally (for example, 438: * if this list is the collection), behavior is unspecified. 439: * 440: * @param c the collection to append 441: * @return true if the list was modified 442: * @throws NullPointerException if c is null 443: * @throws IndexOutOfBoundsException if index < 0 || index > size() 444: */ 445: public boolean addAll(int index, Collection c) 446: { 447: checkBoundsInclusive(index); 448: int csize = c.size(); 449: 450: if (csize == 0) 451: return false; 452: 453: Iterator itr = c.iterator(); 454: 455: // Get the entries just before and after index. If index is at the start 456: // of the list, BEFORE is null. If index is at the end of the list, AFTER 457: // is null. If the list is empty, both are null. 458: Entry after = null; 459: Entry before = null; 460: if (index != size) 461: { 462: after = getEntry(index); 463: before = after.previous; 464: } 465: else 466: before = last; 467: 468: // Create the first new entry. We do not yet set the link from `before' 469: // to the first entry, in order to deal with the case where (c == this). 470: // [Actually, we don't have to handle this case to fufill the 471: // contract for addAll(), but Sun's implementation appears to.] 472: Entry e = new Entry(itr.next()); 473: e.previous = before; 474: Entry prev = e; 475: Entry firstNew = e; 476: 477: // Create and link all the remaining entries. 478: for (int pos = 1; pos < csize; pos++) 479: { 480: e = new Entry(itr.next()); 481: e.previous = prev; 482: prev.next = e; 483: prev = e; 484: } 485: 486: // Link the new chain of entries into the list. 487: modCount++; 488: size += csize; 489: prev.next = after; 490: if (after != null) 491: after.previous = e; 492: else 493: last = e; 494: 495: if (before != null) 496: before.next = firstNew; 497: else 498: first = firstNew; 499: return true; 500: } 501: 502: /** 503: * Remove all elements from this list. 504: */ 505: public void clear() 506: { 507: if (size > 0) 508: { 509: modCount++; 510: first = null; 511: last = null; 512: size = 0; 513: } 514: } 515: 516: /** 517: * Return the element at index. 518: * 519: * @param index the place to look 520: * @return the element at index 521: * @throws IndexOutOfBoundsException if index < 0 || index >= size() 522: */ 523: public T get(int index) 524: { 525: checkBoundsExclusive(index); 526: return getEntry(index).data; 527: } 528: 529: /** 530: * Replace the element at the given location in the list. 531: * 532: * @param index which index to change 533: * @param o the new element 534: * @return the prior element 535: * @throws IndexOutOfBoundsException if index < 0 || index >= size() 536: */ 537: public T set(int index, T o) 538: { 539: checkBoundsExclusive(index); 540: Entry e = getEntry(index); 541: T old = e.data; 542: e.data = o; 543: return old; 544: } 545: 546: /** 547: * Inserts an element in the given position in the list. 548: * 549: * @param index where to insert the element 550: * @param o the element to insert 551: * @throws IndexOutOfBoundsException if index < 0 || index > size() 552: */ 553: public void add(int index, T o) 554: { 555: checkBoundsInclusive(index); 556: Entry e = new Entry(o); 557: 558: if (index < size) 559: { 560: modCount++; 561: Entry after = getEntry(index); 562: e.next = after; 563: e.previous = after.previous; 564: if (after.previous == null) 565: first = e; 566: else 567: after.previous.next = e; 568: after.previous = e; 569: size++; 570: } 571: else 572: addLastEntry(e); 573: } 574: 575: /** 576: * Removes the element at the given position from the list. 577: * 578: * @param index the location of the element to remove 579: * @return the removed element 580: * @throws IndexOutOfBoundsException if index < 0 || index > size() 581: */ 582: public T remove(int index) 583: { 584: checkBoundsExclusive(index); 585: Entry e = getEntry(index); 586: removeEntry(e); 587: return e.data; 588: } 589: 590: /** 591: * Returns the first index where the element is located in the list, or -1. 592: * 593: * @param o the element to look for 594: * @return its position, or -1 if not found 595: */ 596: public int indexOf(Object o) 597: { 598: int index = 0; 599: Entry e = first; 600: while (e != null) 601: { 602: if (equals(o, e.data)) 603: return index; 604: index++; 605: e = e.next; 606: } 607: return -1; 608: } 609: 610: /** 611: * Returns the last index where the element is located in the list, or -1. 612: * 613: * @param o the element to look for 614: * @return its position, or -1 if not found 615: */ 616: public int lastIndexOf(Object o) 617: { 618: int index = size - 1; 619: Entry e = last; 620: while (e != null) 621: { 622: if (equals(o, e.data)) 623: return index; 624: index--; 625: e = e.previous; 626: } 627: return -1; 628: } 629: 630: /** 631: * Obtain a ListIterator over this list, starting at a given index. The 632: * ListIterator returned by this method supports the add, remove and set 633: * methods. 634: * 635: * @param index the index of the element to be returned by the first call to 636: * next(), or size() to be initially positioned at the end of the list 637: * @throws IndexOutOfBoundsException if index < 0 || index > size() 638: */ 639: public ListIterator listIterator(int index) 640: { 641: checkBoundsInclusive(index); 642: return new LinkedListItr(index); 643: } 644: 645: /** 646: * Create a shallow copy of this LinkedList (the elements are not cloned). 647: * 648: * @return an object of the same class as this object, containing the 649: * same elements in the same order 650: */ 651: public Object clone() 652: { 653: LinkedList copy = null; 654: try 655: { 656: copy = (LinkedList) super.clone(); 657: } 658: catch (CloneNotSupportedException ex) 659: { 660: } 661: copy.clear(); 662: copy.addAll(this); 663: return copy; 664: } 665: 666: /** 667: * Returns an array which contains the elements of the list in order. 668: * 669: * @return an array containing the list elements 670: */ 671: public Object[] toArray() 672: { 673: Object[] array = new Object[size]; 674: Entry e = first; 675: for (int i = 0; i < size; i++) 676: { 677: array[i] = e.data; 678: e = e.next; 679: } 680: return array; 681: } 682: 683: /** 684: * Returns an Array whose component type is the runtime component type of 685: * the passed-in Array. The returned Array is populated with all of the 686: * elements in this LinkedList. If the passed-in Array is not large enough 687: * to store all of the elements in this List, a new Array will be created 688: * and returned; if the passed-in Array is larger than the size 689: * of this List, then size() index will be set to null. 690: * 691: * @param a the passed-in Array 692: * @return an array representation of this list 693: * @throws ArrayStoreException if the runtime type of a does not allow 694: * an element in this list 695: * @throws NullPointerException if a is null 696: */ 697: public S[] toArray(S[] a) 698: { 699: if (a.length < size) 700: a = (S[]) Array.newInstance(a.getClass().getComponentType(), size); 701: else if (a.length > size) 702: a[size] = null; 703: Entry e = first; 704: for (int i = 0; i < size; i++) 705: { 706: a[i] = (S) e.data; 707: e = e.next; 708: } 709: return a; 710: } 711: 712: /** 713: * Adds the specified element to the end of the list. 714: * 715: * @param value the value to add. 716: * @return true. 717: * @since 1.5 718: */ 719: public boolean offer(T value) 720: { 721: return add(value); 722: } 723: 724: /** 725: * Returns the first element of the list without removing 726: * it. 727: * 728: * @return the first element of the list. 729: * @throws NoSuchElementException if the list is empty. 730: * @since 1.5 731: */ 732: public T element() 733: { 734: return getFirst(); 735: } 736: 737: /** 738: * Returns the first element of the list without removing 739: * it. 740: * 741: * @return the first element of the list, or null 742: * if the list is empty. 743: * @since 1.5 744: */ 745: public T peek() 746: { 747: if (size == 0) 748: return null; 749: return getFirst(); 750: } 751: 752: /** 753: * Removes and returns the first element of the list. 754: * 755: * @return the first element of the list, or null 756: * if the list is empty. 757: * @since 1.5 758: */ 759: public T poll() 760: { 761: if (size == 0) 762: return null; 763: return removeFirst(); 764: } 765: 766: /** 767: * Removes and returns the first element of the list. 768: * 769: * @return the first element of the list. 770: * @throws NoSuchElementException if the list is empty. 771: * @since 1.5 772: */ 773: public T remove() 774: { 775: return removeFirst(); 776: } 777: 778: /** 779: * Serializes this object to the given stream. 780: * 781: * @param s the stream to write to 782: * @throws IOException if the underlying stream fails 783: * @serialData the size of the list (int), followed by all the elements 784: * (Object) in proper order 785: */ 786: private void writeObject(ObjectOutputStream s) throws IOException 787: { 788: s.defaultWriteObject(); 789: s.writeInt(size); 790: Entry e = first; 791: while (e != null) 792: { 793: s.writeObject(e.data); 794: e = e.next; 795: } 796: } 797: 798: /** 799: * Deserializes this object from the given stream. 800: * 801: * @param s the stream to read from 802: * @throws ClassNotFoundException if the underlying stream fails 803: * @throws IOException if the underlying stream fails 804: * @serialData the size of the list (int), followed by all the elements 805: * (Object) in proper order 806: */ 807: private void readObject(ObjectInputStream s) 808: throws IOException, ClassNotFoundException 809: { 810: s.defaultReadObject(); 811: int i = s.readInt(); 812: while (--i >= 0) 813: addLastEntry(new Entry((T) s.readObject())); 814: } 815: 816: /** 817: * A ListIterator over the list. This class keeps track of its 818: * position in the list and the two list entries it is between. 819: * 820: * @author Original author unknown 821: * @author Eric Blake ([email protected]) 822: */ 823: private final class LinkedListItr 824: implements ListIterator 825: { 826: /** Number of modifications we know about. */ 827: private int knownMod = modCount; 828: 829: /** Entry that will be returned by next(). */ 830: private Entry next; 831: 832: /** Entry that will be returned by previous(). */ 833: private Entry previous; 834: 835: /** Entry that will be affected by remove() or set(). */ 836: private Entry lastReturned; 837: 838: /** Index of `next'. */ 839: private int position; 840: 841: /** 842: * Initialize the iterator. 843: * 844: * @param index the initial index 845: */ 846: LinkedListItr(int index) 847: { 848: if (index == size) 849: { 850: next = null; 851: previous = (Entry) last; 852: } 853: else 854: { 855: next = (Entry) getEntry(index); 856: previous = next.previous; 857: } 858: position = index; 859: } 860: 861: /** 862: * Checks for iterator consistency. 863: * 864: * @throws ConcurrentModificationException if the list was modified 865: */ 866: private void checkMod() 867: { 868: if (knownMod != modCount) 869: throw new ConcurrentModificationException(); 870: } 871: 872: /** 873: * Returns the index of the next element. 874: * 875: * @return the next index 876: */ 877: public int nextIndex() 878: { 879: return position; 880: } 881: 882: /** 883: * Returns the index of the previous element. 884: * 885: * @return the previous index 886: */ 887: public int previousIndex() 888: { 889: return position - 1; 890: } 891: 892: /** 893: * Returns true if more elements exist via next. 894: * 895: * @return true if next will succeed 896: */ 897: public boolean hasNext() 898: { 899: return (next != null); 900: } 901: 902: /** 903: * Returns true if more elements exist via previous. 904: * 905: * @return true if previous will succeed 906: */ 907: public boolean hasPrevious() 908: { 909: return (previous != null); 910: } 911: 912: /** 913: * Returns the next element. 914: * 915: * @return the next element 916: * @throws ConcurrentModificationException if the list was modified 917: * @throws NoSuchElementException if there is no next 918: */ 919: public I next() 920: { 921: checkMod(); 922: if (next == null) 923: throw new NoSuchElementException(); 924: position++; 925: lastReturned = previous = next; 926: next = lastReturned.next; 927: return lastReturned.data; 928: } 929: 930: /** 931: * Returns the previous element. 932: * 933: * @return the previous element 934: * @throws ConcurrentModificationException if the list was modified 935: * @throws NoSuchElementException if there is no previous 936: */ 937: public I previous() 938: { 939: checkMod(); 940: if (previous == null) 941: throw new NoSuchElementException(); 942: position--; 943: lastReturned = next = previous; 944: previous = lastReturned.previous; 945: return lastReturned.data; 946: } 947: 948: /** 949: * Remove the most recently returned element from the list. 950: * 951: * @throws ConcurrentModificationException if the list was modified 952: * @throws IllegalStateException if there was no last element 953: */ 954: public void remove() 955: { 956: checkMod(); 957: if (lastReturned == null) 958: throw new IllegalStateException(); 959: 960: // Adjust the position to before the removed element, if the element 961: // being removed is behind the cursor. 962: if (lastReturned == previous) 963: position--; 964: 965: next = lastReturned.next; 966: previous = lastReturned.previous; 967: removeEntry((Entry) lastReturned); 968: knownMod++; 969: 970: lastReturned = null; 971: } 972: 973: /** 974: * Adds an element between the previous and next, and advance to the next. 975: * 976: * @param o the element to add 977: * @throws ConcurrentModificationException if the list was modified 978: */ 979: public void add(I o) 980: { 981: checkMod(); 982: modCount++; 983: knownMod++; 984: size++; 985: position++; 986: Entry e = new Entry(o); 987: e.previous = previous; 988: e.next = next; 989: 990: if (previous != null) 991: previous.next = e; 992: else 993: first = (Entry) e; 994: 995: if (next != null) 996: next.previous = e; 997: else 998: last = (Entry) e; 999: 1000: previous = e; 1001: lastReturned = null; 1002: } 1003: 1004: /** 1005: * Changes the contents of the element most recently returned. 1006: * 1007: * @param o the new element 1008: * @throws ConcurrentModificationException if the list was modified 1009: * @throws IllegalStateException if there was no last element 1010: */ 1011: public void set(I o) 1012: { 1013: checkMod(); 1014: if (lastReturned == null) 1015: throw new IllegalStateException(); 1016: lastReturned.data = o; 1017: } 1018: } // class LinkedListItr 1019: 1020: /** 1021: * Obtain an Iterator over this list in reverse sequential order. 1022: * 1023: * @return an Iterator over the elements of the list in 1024: * reverse order. 1025: * @since 1.6 1026: */ 1027: public Iterator descendingIterator() 1028: { 1029: return new Iterator() 1030: { 1031: /** Number of modifications we know about. */ 1032: private int knownMod = modCount; 1033: 1034: /** Entry that will be returned by next(). */ 1035: private Entry next = last; 1036: 1037: /** Entry that will be affected by remove() or set(). */ 1038: private Entry lastReturned; 1039: 1040: /** Index of `next'. */ 1041: private int position = size() - 1; 1042: 1043: // This will get inlined, since it is private. 1044: /** 1045: * Checks for modifications made to the list from 1046: * elsewhere while iteration is in progress. 1047: * 1048: * @throws ConcurrentModificationException if the 1049: * list has been modified elsewhere. 1050: */ 1051: private void checkMod() 1052: { 1053: if (knownMod != modCount) 1054: throw new ConcurrentModificationException(); 1055: } 1056: 1057: /** 1058: * Tests to see if there are any more objects to 1059: * return. 1060: * 1061: * @return true if the start of the list has not yet been 1062: * reached. 1063: */ 1064: public boolean hasNext() 1065: { 1066: return next != null; 1067: } 1068: 1069: /** 1070: * Retrieves the next object from the list. 1071: * 1072: * @return The next object. 1073: * @throws NoSuchElementException if there are 1074: * no more objects to retrieve. 1075: * @throws ConcurrentModificationException if the 1076: * list has been modified elsewhere. 1077: */ 1078: public T next() 1079: { 1080: checkMod(); 1081: if (next == null) 1082: throw new NoSuchElementException(); 1083: --position; 1084: lastReturned = next; 1085: next = lastReturned.previous; 1086: return lastReturned.data; 1087: } 1088: 1089: /** 1090: * Removes the last object retrieved by next() 1091: * from the list, if the list supports object removal. 1092: * 1093: * @throws ConcurrentModificationException if the list 1094: * has been modified elsewhere. 1095: * @throws IllegalStateException if the iterator is positioned 1096: * before the start of the list or the last object has already 1097: * been removed. 1098: */ 1099: public void remove() 1100: { 1101: checkMod(); 1102: if (lastReturned == null) 1103: throw new IllegalStateException(); 1104: removeEntry(lastReturned); 1105: lastReturned = null; 1106: ++knownMod; 1107: } 1108: }; 1109: } 1110: 1111: /** 1112: * Inserts the specified element at the front of the list. 1113: * 1114: * @param value the element to insert. 1115: * @return true. 1116: * @since 1.6 1117: */ 1118: public boolean offerFirst(T value) 1119: { 1120: addFirst(value); 1121: return true; 1122: } 1123: 1124: /** 1125: * Inserts the specified element at the end of the list. 1126: * 1127: * @param value the element to insert. 1128: * @return true. 1129: * @since 1.6 1130: */ 1131: public boolean offerLast(T value) 1132: { 1133: return add(value); 1134: } 1135: 1136: /** 1137: * Returns the first element of the list without removing 1138: * it. 1139: * 1140: * @return the first element of the list, or null 1141: * if the list is empty. 1142: * @since 1.6 1143: */ 1144: public T peekFirst() 1145: { 1146: return peek(); 1147: } 1148: 1149: /** 1150: * Returns the last element of the list without removing 1151: * it. 1152: * 1153: * @return the last element of the list, or null 1154: * if the list is empty. 1155: * @since 1.6 1156: */ 1157: public T peekLast() 1158: { 1159: if (size == 0) 1160: return null; 1161: return getLast(); 1162: } 1163: 1164: /** 1165: * Removes and returns the first element of the list. 1166: * 1167: * @return the first element of the list, or null 1168: * if the list is empty. 1169: * @since 1.6 1170: */ 1171: public T pollFirst() 1172: { 1173: return poll(); 1174: } 1175: 1176: /** 1177: * Removes and returns the last element of the list. 1178: * 1179: * @return the last element of the list, or null 1180: * if the list is empty. 1181: * @since 1.6 1182: */ 1183: public T pollLast() 1184: { 1185: if (size == 0) 1186: return null; 1187: return removeLast(); 1188: } 1189: 1190: /** 1191: * Pops an element from the stack by removing and returning 1192: * the first element in the list. This is equivalent to 1193: * calling {@link #removeFirst()}. 1194: * 1195: * @return the top of the stack, which is the first element 1196: * of the list. 1197: * @throws NoSuchElementException if the list is empty. 1198: * @since 1.6 1199: * @see #removeFirst() 1200: */ 1201: public T pop() 1202: { 1203: return removeFirst(); 1204: } 1205: 1206: /** 1207: * Pushes an element on to the stack by adding it to the 1208: * front of the list. This is equivalent to calling 1209: * {@link #addFirst(T)}. 1210: * 1211: * @param value the element to push on to the stack. 1212: * @throws NoSuchElementException if the list is empty. 1213: * @since 1.6 1214: * @see #addFirst(T) 1215: */ 1216: public void push(T value) 1217: { 1218: addFirst(value); 1219: } 1220: 1221: /** 1222: * Removes the first occurrence of the specified element 1223: * from the list, when traversing the list from head to 1224: * tail. The list is unchanged if the element is not found. 1225: * This is equivalent to calling {@link #remove(Object)}. 1226: * 1227: * @param o the element to remove. 1228: * @return true if an instance of the object was removed. 1229: * @since 1.6 1230: */ 1231: public boolean removeFirstOccurrence(Object o) 1232: { 1233: return remove(o); 1234: } 1235: 1236: /** 1237: * Removes the last occurrence of the specified element 1238: * from the list, when traversing the list from head to 1239: * tail. The list is unchanged if the element is not found. 1240: * 1241: * @param o the element to remove. 1242: * @return true if an instance of the object was removed. 1243: * @since 1.6 1244: */ 1245: public boolean removeLastOccurrence(Object o) 1246: { 1247: Entry e = last; 1248: while (e != null) 1249: { 1250: if (equals(o, e.data)) 1251: { 1252: removeEntry(e); 1253: return true; 1254: } 1255: e = e.previous; 1256: } 1257: return false; 1258: } 1259: 1260: }







你可能感兴趣的:(JAVA和J2EE,数据结构)