LinkedList源码分析和实例应用

1、 LinkedList介绍

  • LinkedList是继承于AbstractSequentialList抽象类,它也可以被当作堆栈、队列或者双端队列使用。
  • LinkedList实现了Deque接口,即能将LinkedList当作双端队列使用
  • LinkedList实现 List 接口,能对它进行队列操作。
  • LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆。
  • LinkedList 实现java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。
  • LinkedList 是非同步的。
  • AbstractSequentialList 实现了get(int index)、set(int index, E element)、add(int index, E element) 和 remove(int index)这些函数。这些接口都是随机访问List的,LinkedList是双向链表;既然它继承于AbstractSequentialList,就相当于已经实现了“get(int index)这些接口

2、LinkedList数据结构

 

1 java.lang.Object
2    ↳     java.util.AbstractCollection<E>
3          ↳     java.util.AbstractList<E>
4                ↳     java.util.AbstractSequentialList<E>
5                      ↳     java.util.LinkedList<E>
6 
7 public class LinkedList<E>
8     extends AbstractSequentialList<E>
9     implements List<E>, Deque<E>, Cloneable, java.io.Serializable {}

 

 

 LinkedList的本质是双向链表。
(01) LinkedList继承于AbstractSequentialList,并且实现了Dequeue接口。
(02) LinkedList包含两个重要的成员:header 和 size。
  header是双向链表的表头,它是双向链表节点所对应的类Entry的实例。Entry中包含成员变量: previous, next, element。其中,previous是该节    点的上一个节点,next是该节点的下一个节点,element是该节点所包含的值。
  size是双向链表中节点的个数。

3、LinkedList的源码分析

 

为了更了解LinkedList的原理,下面对LinkedList源码代码作出分析

 

在阅读源码之前,先对LinkedList的整体实现进行大致说明:
    LinkedList是通过双向链表去实现的。既然是双向链表,那么它的顺序访问会非常高效,而随机访问效率比较低
    既然LinkedList实现了List接口{也就是说,它实现了get(int location)、remove(int location)等“根据索引值来获取、删除节点的函数”}。LinkedList是如何实现List的这些接口的,如何将“双向链表和索引值联系起来的”?
    实际原理非常简单,它就是通过一个计数索引值来实现的。例如,当我们调用get(int location)时,首先会比较“location”和“双向链表长度的1/2”;若前者大,则从链表头开始往后查找,直到location位置;否则,从链表末尾开始先前查找,直到location位置。这就是“双线链表和索引值联系起来”的方法。

  1 package java.util;
  2 
  3 public class LinkedList<E>
  4     extends AbstractSequentialList<E>
  5     implements List<E>, Deque<E>, Cloneable, java.io.Serializable
  6 {
  7     // 链表的表头,表头不包含任何数据。Entry是个链表类数据结构。
  8     private transient Entry<E> header = new Entry<E>(null, null, null);
  9 
 10     // LinkedList中元素个数
 11     private transient int size = 0;
 12 
 13     // 默认构造函数:创建一个空的链表
 14     public LinkedList() {
 15         header.next = header.previous = header;
 16     }
 17 
 18     // 包含“集合”的构造函数:创建一个包含“集合”的LinkedList
 19     public LinkedList(Collection<? extends E> c) {
 20         this();
 21         addAll(c);
 22     }
 23 
 24     // 获取LinkedList的第一个元素
 25     public E getFirst() {
 26         if (size==0)
 27             throw new NoSuchElementException();
 28 
 29         // 链表的表头header中不包含数据。
 30         // 这里返回header所指下一个节点所包含的数据。
 31         return header.next.element;
 32     }
 33 
 34     // 获取LinkedList的最后一个元素
 35     public E getLast()  {
 36         if (size==0)
 37             throw new NoSuchElementException();
 38 
 39         // 由于LinkedList是双向链表;而表头header不包含数据。
 40         // 因而,这里返回表头header的前一个节点所包含的数据。
 41         return header.previous.element;
 42     }
 43 
 44     // 删除LinkedList的第一个元素
 45     public E removeFirst() {
 46         return remove(header.next);
 47     }
 48 
 49     // 删除LinkedList的最后一个元素
 50     public E removeLast() {
 51         return remove(header.previous);
 52     }
 53 
 54     // 将元素添加到LinkedList的起始位置
 55     public void addFirst(E e) {
 56         addBefore(e, header.next);
 57     }
 58 
 59     // 将元素添加到LinkedList的结束位置
 60     public void addLast(E e) {
 61         addBefore(e, header);
 62     }
 63 
 64     // 判断LinkedList是否包含元素(o)
 65     public boolean contains(Object o) {
 66         return indexOf(o) != -1;
 67     }
 68 
 69     // 返回LinkedList的大小
 70     public int size() {
 71         return size;
 72     }
 73 
 74     // 将元素(E)添加到LinkedList中,每次添加都是添加在双向链表的最后面位置
 75     public boolean add(E e) {
 76         // 将节点(节点数据是e)添加到表头(header)之前。
 77         // 即,将节点添加到双向链表的末端。
 78         addBefore(e, header);
 79         return true;
 80     }
 81 
 82     // 从LinkedList中删除元素(o)
 83     // 从链表开始查找,如存在元素(o)则删除该元素并返回true;
 84     // 否则,返回false。
 85     public boolean remove(Object o) {
 86         if (o==null) {
 87             // 若o为null的删除情况
 88             for (Entry<E> e = header.next; e != header; e = e.next) {
 89                 if (e.element==null) {
 90                     remove(e);
 91                     return true;
 92                 }
 93             }
 94         } else {
 95             // 若o不为null的删除情况
 96             for (Entry<E> e = header.next; e != header; e = e.next) {
 97                 if (o.equals(e.element)) {
 98                     remove(e);
 99                     return true;
100                 }
101             }
102         }
103         return false;
104     }
105 
106     // 将“集合(c)”添加到LinkedList中。
107     // 实际上,代码中可以看出是从双向链表的末尾开始,将“集合(c)”添加到双向链表中。
108     public boolean addAll(Collection<? extends E> c) {
109         return addAll(size, c);
110     }
111 
112     // 从双向链表的index(指定位置)开始,将“集合(c)”添加到双向链表中。
113     public boolean addAll(int index, Collection<? extends E> c) {
114         if (index < 0 || index > size)
115             throw new IndexOutOfBoundsException("Index: "+index+
116                                                 ", Size: "+size);
117         //先将集合C转换成对象数组
118         Object[] a = c.toArray();
119         // 获取集合的长度
120         int numNew = a.length;
121         if (numNew==0)
122             return false;
123         modCount++;
124 
125         // 设置“当前要插入节点的后一个节点”,首先判断当前带插入位置是不是链表尾部
126         Entry<E> successor = (index==size ? header : entry(index));
127         // 设置“当前要插入节点的前一个节点”
128         Entry<E> predecessor = successor.previous;
129         // 将集合(c)全部插入双向链表中
130         for (int i=0; i<numNew; i++) {
131             //这里使用构造器的方法创建一个entry节点时候直接指明该节点前驱和后继指针的值
132             Entry<E> e = new Entry<E>((E)a[i], successor, predecessor);
133             predecessor.next = e;
134             predecessor = e;
135         }
136         successor.previous = predecessor;
137 
138         // 调整LinkedList的实际大小
139         size += numNew;
140         return true;
141     }
142 
143     // 清空双向链表
144     public void clear() {
145         Entry<E> e = header.next;
146         // 从表头开始,逐个向后遍历;对遍历到的节点执行一下操作:
147         // (01) 设置该节点的前驱指针和后继指针都为null 
148         // (02) 设置当前节点的内容为null 
149         // (03) 设置后一个节点为“新的当前节点”,这样依次循环一边把全部元素全部赋为空
150         while (e != header) {
151             Entry<E> next = e.next;
152             e.next = e.previous = null;
153             e.element = null;
154             e = next;
155         }
156         //把元素节点赋值为空之后,还要把头节点的next指针和previous指针都指向头节点
157         header.next = header.previous = header;
158         // 设置大小为0
159         size = 0;
160         modCount++;
161     }
162 
163     // 返回LinkedList指定位置的元素
164     public E get(int index) {
165         return entry(index).element;
166     }
167 
168     // 设置index位置对应的节点的值为element
169     public E set(int index, E element) {
170         Entry<E> e = entry(index);
171         E oldVal = e.element;
172         e.element = element;
173         return oldVal;
174     }
175  
176     // 在index前添加节点,且节点的值为element
177     public void add(int index, E element) {
178         addBefore(element, (index==size ? header : entry(index)));
179     }
180 
181     // 删除index位置的节点
182     public E remove(int index) {
183         return remove(entry(index));
184     }
185 
186     // 获取双向链表中指定位置的节点元素
187     private Entry<E> entry(int index) {
188         if (index < 0 || index >= size)
189             throw new IndexOutOfBoundsException("Index: "+index+
190                                                 ", Size: "+size);
191         Entry<E> e = header;
192         // 获取index处的节点。
193         // 若index < 双向链表长度的1/2,则从前先后查找;
194         // 否则,从后向前查找。
195         if (index < (size >> 1)) {
196             for (int i = 0; i <= index; i++)
197                 e = e.next;
198         } else {
199             for (int i = size; i > index; i--)
200                 e = e.previous;
201         }
202         return e;
203     }
204 
205     // 从前向后一个一个的查找,返回“值为对象(o)的节点对应的索引”
206     // 不存在就返回-1
207     public int indexOf(Object o) {
208         int index = 0;
209         if (o==null) {
210             for (Entry e = header.next; e != header; e = e.next) {
211                 if (e.element==null)
212                     return index;
213                 index++;
214             }
215         } else {
216             for (Entry e = header.next; e != header; e = e.next) {
217                 if (o.equals(e.element))
218                     return index;
219                 index++;
220             }
221         }
222         return -1;
223     }
224 
225     // 从后向前查找,返回“值为对象(o)的节点对应的索引”
226     // 不存在就返回-1
227     public int lastIndexOf(Object o) {
228         int index = size;
229         if (o==null) {
230             for (Entry e = header.previous; e != header; e = e.previous) {
231                 index--;
232                 if (e.element==null)
233                     return index;
234             }
235         } else {
236             for (Entry e = header.previous; e != header; e = e.previous) {
237                 index--;
238                 if (o.equals(e.element))
239                     return index;
240             }
241         }
242         return -1;
243     }
244 
245     // 返回第一个节点
246     // 若LinkedList的大小为0,则返回null
247     public E peek() {
248         if (size==0)
249             return null;
250         return getFirst();
251     }
252 
253     // 返回第一个节点,这里没有处理双向链表为空的情况
254     // 若LinkedList的大小为0,则抛出异常
255     public E element() {
256         return getFirst();
257     }
258 
259     // 删除并返回第一个节点
260     // 若LinkedList的大小为0,则返回null
261     public E poll() {
262         if (size==0)
263             return null;
264         return removeFirst();
265     }
266 
267     // 将e添加双向链表末尾
268     public boolean offer(E e) {
269         return add(e);
270     }
271 
272     // 将e添加双向链表开头
273     public boolean offerFirst(E e) {
274         addFirst(e);
275         return true;
276     }
277 
278     // 将e添加双向链表末尾
279     public boolean offerLast(E e) {
280         addLast(e);
281         return true;
282     }
283 
284     // 返回第一个节点
285     // 若LinkedList的大小为0,则返回null
286     public E peekFirst() {
287         if (size==0)
288             return null;
289         return getFirst();
290     }
291 
292     // 返回最后一个节点
293     // 若LinkedList的大小为0,则返回null
294     public E peekLast() {
295         if (size==0)
296             return null;
297         return getLast();
298     }
299 
300     // 删除并返回第一个节点
301     // 若LinkedList的大小为0,则返回null
302     public E pollFirst() {
303         if (size==0)
304             return null;
305         return removeFirst();
306     }
307 
308     // 删除并返回最后一个节点
309     // 若LinkedList的大小为0,则返回null
310     public E pollLast() {
311         if (size==0)
312             return null;
313         return removeLast();
314     }
315 
316     // 将e插入到双向链表开头
317     public void push(E e) {
318         addFirst(e);
319     }
320 
321     // 删除并返回第一个节点
322     public E pop() {
323         return removeFirst();
324     }
325 
326     // 从LinkedList开始向后查找,删除第一个值为元素(o)的节点
327     // 从链表开始查找,如存在节点的值为元素(o)的节点,则删除该节点
328     public boolean removeFirstOccurrence(Object o) {
329         return remove(o);
330     }
331 
332     // 从LinkedList末尾向前查找,删除第一个值为元素(o)的节点
333     // 从链表开始查找,如存在节点的值为元素(o)的节点,则删除该节点
334     public boolean removeLastOccurrence(Object o) {
335         if (o==null) {
336             for (Entry<E> e = header.previous; e != header; e = e.previous) {
337                 if (e.element==null) {
338                     remove(e);
339                     return true;
340                 }
341             }
342         } else {
343             for (Entry<E> e = header.previous; e != header; e = e.previous) {
344                 if (o.equals(e.element)) {
345                     remove(e);
346                     return true;
347                 }
348             }
349         }
350         return false;
351     }
352 
353     // 返回“index到末尾的全部节点”对应的ListIterator对象(List迭代器)
354     public ListIterator<E> listIterator(int index) {
355         return new ListItr(index);
356     }
357 
358     // List迭代器
359     private class ListItr implements ListIterator<E> {
360         // 上一次返回的节点
361         private Entry<E> lastReturned = header;
362         // 下一个节点
363         private Entry<E> next;
364         // 下一个节点对应的索引值
365         private int nextIndex;
366         // 期望的改变计数。用来实现fail-fast机制。
367         private int expectedModCount = modCount;
368 
369         // 构造函数。
370         // 从index位置开始进行迭代
371         ListItr(int index) {
372             // index的有效性处理
373             if (index < 0 || index > size)
374                 throw new IndexOutOfBoundsException("Index: "+index+ ", Size: "+size);
375             // 若 “index 小于 ‘双向链表长度的一半’”,则从第一个元素开始往后查找;
376             // 否则,从最后一个元素往前查找。
377             if (index < (size >> 1)) {
378                 next = header.next;
379                 for (nextIndex=0; nextIndex<index; nextIndex++)
380                     next = next.next;
381             } else {
382                 next = header;
383                 for (nextIndex=size; nextIndex>index; nextIndex--)
384                     next = next.previous;
385             }
386         }
387 
388         // 是否存在下一个元素
389         public boolean hasNext() {
390             // 通过元素索引是否等于“双向链表大小”来判断是否达到最后。
391             return nextIndex != size;
392         }
393 
394         // 获取下一个元素
395         public E next() {
396             checkForComodification();
397             if (nextIndex == size)
398                 throw new NoSuchElementException();
399 
400             lastReturned = next;
401             // next指向链表的下一个元素
402             next = next.next;
403             nextIndex++;
404             return lastReturned.element;
405         }
406 
407         // 是否存在上一个元素
408         public boolean hasPrevious() {
409             // 通过元素索引是否等于0,来判断是否达到开头。
410             return nextIndex != 0;
411         }
412 
413         // 获取上一个元素
414         public E previous() {
415             if (nextIndex == 0)
416             throw new NoSuchElementException();
417 
418             // next指向链表的上一个元素
419             lastReturned = next = next.previous;
420             nextIndex--;
421             checkForComodification();
422             return lastReturned.element;
423         }
424 
425         // 获取下一个元素的索引
426         public int nextIndex() {
427             return nextIndex;
428         }
429 
430         // 获取上一个元素的索引
431         public int previousIndex() {
432             return nextIndex-1;
433         }
434 
435         // 删除当前元素。
436         // 删除双向链表中的当前节点
437         public void remove() {
438             checkForComodification();
439             Entry<E> lastNext = lastReturned.next;
440             try {
441                 LinkedList.this.remove(lastReturned);
442             } catch (NoSuchElementException e) {
443                 throw new IllegalStateException();
444             }
445             if (next==lastReturned)
446                 next = lastNext;
447             else
448                 nextIndex--;
449             lastReturned = header;
450             expectedModCount++;
451         }
452 
453         // 设置当前节点为e
454         public void set(E e) {
455             if (lastReturned == header)
456                 throw new IllegalStateException();
457             checkForComodification();
458             lastReturned.element = e;
459         }
460 
461         // 将e添加到当前节点的前面
462         public void add(E e) {
463             checkForComodification();
464             lastReturned = header;
465             addBefore(e, next);
466             nextIndex++;
467             expectedModCount++;
468         }
469 
470         // 判断 “modCount和expectedModCount是否相等”,以此来实现fail-fast机制。
471         final void checkForComodification() {
472             if (modCount != expectedModCount)
473             throw new ConcurrentModificationException();
474         }
475     }
476 
477     // 双向链表的节点所对应的数据结构。
478     // 包含3部分:上一节点,下一节点,当前节点值。
479     private static class Entry<E> {
480         // 当前节点所包含的值
481         E element;
482         // 下一个节点
483         Entry<E> next;
484         // 上一个节点
485         Entry<E> previous;
486 
487         /**
488          * 链表节点的构造函数。
489          * 参数说明:
490          *   element  —— 节点所包含的数据
491          *   next      —— 指向下一个节点
492          *   previous —— 指向上一个节点
493          */
494         Entry(E element, Entry<E> next, Entry<E> previous) {
495             this.element = element;
496             this.next = next;
497             this.previous = previous;
498         }
499     }
500 
501     // 将节点(节点数据是e)添加到entry节点之前。
502     private Entry<E> addBefore(E e, Entry<E> entry) {
503         // 新建节点newEntry,将newEntry插入到节点e之前;并且设置newEntry的数据是e
504         Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);
505         newEntry.previous.next = newEntry;
506         newEntry.next.previous = newEntry;
507         // 修改LinkedList大小
508         size++;
509         // 修改LinkedList的修改统计数:用来实现fail-fast机制。
510         modCount++;
511         return newEntry;
512     }
513 
514     // 将节点从链表中删除,链表头结点不带数据元素,并且不能被删除
515     private E remove(Entry<E> e) {
516         if (e == header)
517             throw new NoSuchElementException();
518     //这是删除一个双向链表中元素的具体过程
519         E result = e.element;
520         //先修改待删除节点的指针指向
521         e.previous.next = e.next;
522         e.next.previous = e.previous;
523         //然后再把该节点的指针全部赋值为空
524         e.next = e.previous = null;
525         e.element = null;
526         size--;
527         modCount++;
528         return result;
529     }
530 
531     // 反向迭代器
532     public Iterator<E> descendingIterator() {
533         return new DescendingIterator();
534     }
535 
536     // 反向迭代器实现类。
537     private class DescendingIterator implements Iterator {
538         final ListItr itr = new ListItr(size());
539         // 反向迭代器是否下一个元素。
540         // 实际上是判断双向链表的当前节点是否达到开头
541         public boolean hasNext() {
542             return itr.hasPrevious();
543         }
544         // 反向迭代器获取下一个元素。
545         // 实际上是获取双向链表的前一个节点
546         public E next() {
547             return itr.previous();
548         }
549         // 删除当前节点
550         public void remove() {
551             itr.remove();
552         }
553     }
554 
555 
556     // 返回LinkedList的Object[]数组
557     public Object[] toArray() {
558     // 新建Object[]数组
559     Object[] result = new Object[size];
560         int i = 0;
561         // 将链表中所有节点的数据都添加到Object[]数组中
562         for (Entry<E> e = header.next; e != header; e = e.next)
563             result[i++] = e.element;
564     return result;
565     }
566 
567     // 返回LinkedList的模板数组。所谓模板数组,即可以将T设为任意的数据类型
568     public <T> T[] toArray(T[] a) {
569         // 若数组a的大小 < LinkedList的元素个数(意味着数组a不能容纳LinkedList中全部元素)
570         // 则利用反射新建一个T[]数组,T[]的大小为LinkedList大小,并将该T[]赋值给a。
571         if (a.length < size)
572             a = (T[])java.lang.reflect.Array.newInstance(
573                                 a.getClass().getComponentType(), size);
574         // 将链表中所有节点的数据都添加到数组a中
575         int i = 0;
576         Object[] result = a;
577         for (Entry<E> e = header.next; e != header; e = e.next)
578             result[i++] = e.element;
579 
580         if (a.length > size)
581             a[size] = null;
582 
583         return a;
584     }
585 
586 
587     // 克隆函数。返回LinkedList的克隆对象。
588     public Object clone() {
589         LinkedList<E> clone = null;
590         // 克隆一个LinkedList克隆对象
591         try {
592             clone = (LinkedList<E>) super.clone();
593         } catch (CloneNotSupportedException e) {
594             throw new InternalError();
595         }
596 
597         // 新建LinkedList表头节点,紧接着把原链表的初始化属性全部赋值给新建的双线链表
598         clone.header = new Entry<E>(null, null, null);
599         clone.header.next = clone.header.previous = clone.header;
600         clone.size = 0;
601         clone.modCount = 0;
602 
603         // 将链表中所有节点的数据都添加到克隆对象中
604         for (Entry<E> e = header.next; e != header; e = e.next)
605             clone.add(e.element);
606 
607         return clone;
608     }
609 
610     // java.io.Serializable的写入函数
611     // 将LinkedList的“容量,所有的元素值”都写入到输出流中
612     private void writeObject(java.io.ObjectOutputStream s)
613         throws java.io.IOException {
614         // Write out any hidden serialization magic
615         s.defaultWriteObject();
616 
617         // 写入“容量”
618         s.writeInt(size);
619 
620         // 将链表中所有节点的数据都写入到输出流中
621         for (Entry e = header.next; e != header; e = e.next)
622             s.writeObject(e.element);
623     }
624 
625     // java.io.Serializable的读取函数:根据写入方式反向读出
626     // 先将LinkedList的“容量”读出,然后将“所有的元素值”读出
627     private void readObject(java.io.ObjectInputStream s)
628         throws java.io.IOException, ClassNotFoundException {
629         // Read in any hidden serialization magic
630         s.defaultReadObject();
631 
632         // 从输入流中读取“容量”
633         int size = s.readInt();
634 
635         // 首先新建一个链表表头节点
636         header = new Entry<E>(null, null, null);
637         header.next = header.previous = header;
638 
639         // 从输入流中将“所有的元素值”并逐个添加到链表中
640         for (int i=0; i<size; i++)
641             addBefore((E)s.readObject(), header);
642     }
643 
644 }
View Code

(01) LinkedList 实际上是通过双向链表去实现的。
      它包含一个非常重要的内部类:Entry。Entry是双向链表节点所对应的数据结构,它包括的属性有:当前节点所包含的值上一个节点下一个节点
(02) 从LinkedList的实现方式中可以发现,它不存在LinkedList容量不足的问题。
(03) LinkedList的克隆函数,即是将全部元素克隆到一个新的LinkedList对象中。
(04) LinkedList实现java.io.Serializable。当写入到输出流时,先写入“容量”,再依次写入“每一个节点保护的值”;当读出输入流时,先读取“容量”,再依次读取“每一个元素”。
(05) 由于LinkedList实现了Deque,而Deque接口定义了在双端队列两端访问元素的方法。提供插入、移除和检查元素的方法。每种方法都存在两种形式:一种形式在操作失败时抛出异常,另一种形式返回一个特殊值(null 或 false,具体取决于操作)。

 4、LinkedList遍历方式总结和比较

LinkedList支持多种遍历方式。

  • 通过迭代器遍历。即通过Iterator去遍历。
  • 通过快速随机访问遍历LinkedList
  • 通过另外一种for循环来遍历LinkedList
  • 通过pollFirst()来遍历LinkedList
  • 通过pollLast()来遍历LinkedList
  • 通过removeFirst()来遍历LinkedList
  • 通过removeLast()来遍历LinkedList

建议不要采用随机访问的方式去遍历LinkedList,而采用逐个遍历的方式。遍历LinkedList时,使用removeFist()或removeLast()效率最高。但用它们遍历时,会删除原始数据;若单纯只读取,而不删除,应该使用第3种遍历方式。
无论如何,千万不要通过随机访问去遍历LinkedList!

5、LinkedList的常用API测试实例

 

  1 import java.util.List;
  2 import java.util.Iterator;
  3 import java.util.LinkedList;
  4 import java.util.NoSuchElementException;
  5 
  6 /*
  7  *  LinkedList测试程序。
  8  */
  9 public class LinkedListTest {
 10     public static void main(String[] args) {
 11         // 测试LinkedList的API
 12         testLinkedListAPIs() ;
 13 
 14         // 将LinkedList当作 LIFO(后进先出)的堆栈
 15         useLinkedListAsLIFO();
 16 
 17         // 将LinkedList当作 FIFO(先进先出)的队列
 18         useLinkedListAsFIFO();
 19     }
 20     
 21     /*
 22      * 测试LinkedList中部分API
 23      */
 24     private static void testLinkedListAPIs() {
 25         String val = null;
 26         //LinkedList llist;
 27         //llist.offer("10");
 28         // 新建一个LinkedList
 29         LinkedList llist = new LinkedList();
 30         //---- 添加操作 ----
 31         // 依次添加1,2,3
 32         llist.add("1");
 33         llist.add("2");
 34         llist.add("3");
 35 
 36         // 将“4”添加到第一个位置
 37         llist.add(1, "4");
 38         
 39 
 40         System.out.println("\nTest \"addFirst(), removeFirst(), getFirst()\"");
 41         // (01) 将“10”添加到第一个位置。  失败的话,抛出异常!
 42         llist.addFirst("10");
 43         System.out.println("llist:"+llist);
 44         // (02) 将第一个元素删除。        失败的话,抛出异常!
 45         System.out.println("llist.removeFirst():"+llist.removeFirst());
 46         System.out.println("llist:"+llist);
 47         // (03) 获取第一个元素。          失败的话,抛出异常!
 48         System.out.println("llist.getFirst():"+llist.getFirst());
 49 
 50 
 51         System.out.println("\nTest \"offerFirst(), pollFirst(), peekFirst()\"");
 52         // (01) 将“10”添加到第一个位置。  返回true。
 53         llist.offerFirst("10");
 54         System.out.println("llist:"+llist);
 55         // (02) 将第一个元素删除。        失败的话,返回null。
 56         System.out.println("llist.pollFirst():"+llist.pollFirst());
 57         System.out.println("llist:"+llist);
 58         // (03) 获取第一个元素。          失败的话,返回null。
 59         System.out.println("llist.peekFirst():"+llist.peekFirst());
 60     
 61 
 62         System.out.println("\nTest \"addLast(), removeLast(), getLast()\"");
 63         // (01) 将“20”添加到最后一个位置。  失败的话,抛出异常!
 64         llist.addLast("20");
 65         System.out.println("llist:"+llist);
 66         // (02) 将最后一个元素删除。        失败的话,抛出异常!
 67         System.out.println("llist.removeLast():"+llist.removeLast());
 68         System.out.println("llist:"+llist);
 69         // (03) 获取最后一个元素。          失败的话,抛出异常!
 70         System.out.println("llist.getLast():"+llist.getLast());
 71 
 72 
 73         System.out.println("\nTest \"offerLast(), pollLast(), peekLast()\"");
 74         // (01) 将“20”添加到第一个位置。  返回true。
 75         llist.offerLast("20");
 76         System.out.println("llist:"+llist);
 77         // (02) 将第一个元素删除。        失败的话,返回null。
 78         System.out.println("llist.pollLast():"+llist.pollLast());
 79         System.out.println("llist:"+llist);
 80         // (03) 获取第一个元素。          失败的话,返回null。
 81         System.out.println("llist.peekLast():"+llist.peekLast());
 82 
 83          
 84 
 85         // 将第3个元素设置300。不建议在LinkedList中使用此操作,因为效率低!
 86         llist.set(2, "300");
 87         // 获取第3个元素。不建议在LinkedList中使用此操作,因为效率低!
 88         System.out.println("\nget(3):"+llist.get(2));
 89 
 90 
 91         // ---- toArray(T[] a) ----
 92         // 将LinkedList转行为数组
 93         String[] arr = (String[])llist.toArray(new String[0]);
 94         for (String str:arr) 
 95             System.out.println("str:"+str);
 96 
 97         // 输出大小
 98         System.out.println("size:"+llist.size());
 99         // 清空LinkedList
100         llist.clear();
101         // 判断LinkedList是否为空
102         System.out.println("isEmpty():"+llist.isEmpty()+"\n");
103 
104     }
105 
106     /**
107      * 将LinkedList当作 LIFO(后进先出)的堆栈
108      */
109     private static void useLinkedListAsLIFO() {
110         System.out.println("\nuseLinkedListAsLIFO");
111         // 新建一个LinkedList
112         LinkedList stack = new LinkedList();
113 
114         // 将1,2,3,4添加到堆栈中
115         stack.push("1");
116         stack.push("2");
117         stack.push("3");
118         stack.push("4");
119         // 打印“栈”
120         System.out.println("stack:"+stack);
121 
122         // 删除“栈顶元素”
123         System.out.println("stack.pop():"+stack.pop());
124         
125         // 取出“栈顶元素”
126         System.out.println("stack.peek():"+stack.peek());
127 
128         // 打印“栈”
129         System.out.println("stack:"+stack);
130     }
131 
132     /**
133      * 将LinkedList当作 FIFO(先进先出)的队列
134      */
135     private static void useLinkedListAsFIFO() {
136         System.out.println("\nuseLinkedListAsFIFO");
137         // 新建一个LinkedList
138         LinkedList queue = new LinkedList();
139 
140         // 将10,20,30,40添加到队列。每次都是插入到末尾
141         queue.add("10");
142         queue.add("20");
143         queue.add("30");
144         queue.add("40");
145         // 打印“队列”
146         System.out.println("queue:"+queue);
147 
148         // 删除(队列的第一个元素)
149         System.out.println("queue.remove():"+queue.remove());
150     
151         // 读取(队列的第一个元素)
152         System.out.println("queue.element():"+queue.element());
153 
154         // 打印“队列”
155         System.out.println("queue:"+queue);
156     }
157 }
View Code

 

Test "addFirst(), removeFirst(), getFirst()"
llist:[10, 1, 4, 2, 3]
llist.removeFirst():10
llist:[1, 4, 2, 3]
llist.getFirst():1

Test "offerFirst(), pollFirst(), peekFirst()"
llist:[10, 1, 4, 2, 3]
llist.pollFirst():10
llist:[1, 4, 2, 3]
llist.peekFirst():1

Test "addLast(), removeLast(), getLast()"
llist:[1, 4, 2, 3, 20]
llist.removeLast():20
llist:[1, 4, 2, 3]
llist.getLast():3

Test "offerLast(), pollLast(), peekLast()"
llist:[1, 4, 2, 3, 20]
llist.pollLast():20
llist:[1, 4, 2, 3]
llist.peekLast():3

get(3):300
str:1
str:4
str:300
str:3
size:4
isEmpty():true


useLinkedListAsLIFO
stack:[4, 3, 2, 1]
stack.pop():4
stack.peek():3
stack:[3, 2, 1]

useLinkedListAsFIFO
queue:[10, 20, 30, 40]
queue.remove():10
queue.element():20
queue:[20, 30, 40]

 

posted @ 2019-04-07 20:33  包子的百草园  阅读(231)  评论(0编辑  收藏  举报