zoukankan      html  css  js  c++  java
  • 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("
    Test "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("
    Test "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("
    Test "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("
    Test "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("
    get(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()+"
    ");
    103 
    104     }
    105 
    106     /**
    107      * 将LinkedList当作 LIFO(后进先出)的堆栈
    108      */
    109     private static void useLinkedListAsLIFO() {
    110         System.out.println("
    useLinkedListAsLIFO");
    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("
    useLinkedListAsFIFO");
    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]
    
  • 相关阅读:
    通讯技术
    (1)sqlserver2017安装
    c# api身份验证和授权
    ()centos7 安装python36
    python 包管理
    ()centos7 安装mysql8.0
    [bzoj1095][ZJOI2007]Hide 捉迷藏 点分树,动态点分治
    bzoj 3544 [ONTAK2010]Creative Accounting 贪心
    BZOJ4300 绝世好题 dp
    bzoj 4295 [PA2015]Hazard 贪心,暴力
  • 原文地址:https://www.cnblogs.com/BaoZiY/p/10658157.html
Copyright © 2011-2022 走看看