java 集合之LinkedList 构造器 方法 遍历方法 listIterator

java 集合之LinkedList

  • List 和 Deque 接口的双向链表实现。 实现所有可选的列表操作,并允许所有元素(包括空值)。

    • 除了实现 List 接口外,LinkedList 类还为在列表的开头及结尾 get、remove 和 insert 元素提供了统一的命名方法。这些操作允许将链接列表用作堆栈、队列或双端队列。
    • 实现 Deque 接口,为 add、poll 提供先进先出队列操作,以及其他堆栈和双端队列操作。
  • 所有操作都是按照双重链接列表的需要执行的。在列表中编索引的操作将从开头或结尾遍历列表(从靠近指定索引的一端)。

  • 请注意,此实现不是同步的。 如果多个线程并发访问一个链表,并且至少有一个线程在结构上修改了链表,则必须进行外部同步。 (结构修改是添加或删除一个或多个元素的任何操作;仅设置元素的值不是结构修改。)这一般通过对自然封装该列表的对象进行同步操作来完成。

    • 如果不存在此类对象,则应使用 Collections.synchronizedList 方法“包装”该列表。为防止对列表的意外不同步访问, 最好在创建时完成:List list = Collections.synchronizedList(new LinkedList(...));
  • 此类的 iterator 和 listIterator 方法返回的迭代器是快速失败的:在迭代器创建之后,如果从结构上对列表进行修改,除非通过迭代器自身的 remove 或 add 方法,其他任何时间任何方式的修改,迭代器都将抛出 ConcurrentModificationException。 因此,面对并发修改,迭代器快速而干净地失败,而不是冒着在未来不确定的时间出现任意、非确定性行为的风险。

  • 请注意,迭代器的快速失败行为不能得到保证,一般而言,存在不同步的并发修改时,不可能作出任何硬性保证。 快速失败的迭代器会尽最大努力抛出 ConcurrentModificationException。 因此,编写一个依赖此异常来确保其正确性的程序是错误的:迭代器的快速失败行为应该仅用于检测错误。

  • LinkedList可以添加重复数据

构造方法

  • LinkedList() 构造一个空列表。

  • LinkedList(Collection<? extends E> c)按照集合的迭代器返回的顺序构造一个包含指定集合元素的列表。

方法

Modifier and TypeMethodDescription
voidadd (int index, E element)在此列表中的指定位置插入指定元素。
booleanadd (E e)将指定元素附加到此列表的末尾。
booleanaddAll (int index, Collection<? extends E> c)将指定 collection 中的所有元素从指定位置开始插入此列表。
booleanaddAll (Collection<? extends E> c)按照指定集合的迭代器返回的顺序,将指定集合中的所有元素追加到此列表的末尾。
voidaddFirst (E e)将指定元素插入此列表的开头。
voidaddLast (E e)将指定元素添加到此列表的结尾。
voidclear()从此列表中删除所有元素。
Objectclone()返回此 LinkedList 的浅表副本。
booleancontains (Object o)如果此列表包含指定元素,则返回 true。
IteratordescendingIterator()返回以逆向顺序在此双端队列的元素上进行迭代的迭代器。
Eelement()检索但不删除此列表的头部(第一个元素)。
Eget (int index)返回此列表中指定位置的元素。
EgetFirst()返回此列表中的第一个元素。
EgetLast()返回此列表中的最后一个元素。
intindexOf (Object o)返回此列表中指定元素第一次出现的索引,如果此列表不包含该元素,则返回 -1。
intlastIndexOf (Object o)返回此列表中指定元素最后一次出现的索引,如果此列表不包含该元素,则返回 -1。
ListIteratorlistIterator (int index)返回此列表中元素的列表迭代器(以适当的顺序),从列表中的指定位置开始。
booleanoffer (E e)添加指定元素作为此列表的尾部(最后一个元素)。
booleanofferFirst (E e)在此列表的前面插入指定的元素。
booleanofferLast (E e)在此列表的末尾插入指定的元素。
Epeek()检索但不删除此列表的头部(第一个元素)。
EpeekFirst()检索但不删除此列表的第一个元素,如果此列表为空,则返回 null。
EpeekLast()检索但不删除此列表的最后一个元素,如果此列表为空,则返回 null。
Epoll()检索并删除此列表的头部(第一个元素)。
EpollFirst()检索并删除此列表的第一个元素,如果此列表为空,则返回 null。
EpollLast()检索并删除此列表的最后一个元素,如果此列表为空,则返回 null。
Epop()从此列表表示的堆栈中弹出一个元素。
voidpush (E e)将一个元素压入此列表所代表的堆栈。
Eremove()检索并删除此列表的头部(第一个元素)。
Eremove (int index)移除此列表中指定位置的元素。
booleanremove (Object o)从此列表中删除第一次出现的指定元素(如果存在)。
EremoveFirst()从列表中移除并返回第一个元素。
booleanremoveFirstOccurrence (Object o)移除此列表中第一次出现的指定元素(从头到尾遍历列表时)。
EremoveLast()从列表中移除并返回最后一个元素。
booleanremoveLastOccurrence (Object o)移除此列表中指定元素的最后一次出现(从头到尾遍历列表时)。
Eset (int index, E element)用指定的元素替换此列表中指定位置的元素。返回以前在指定位置的元素
intsize()返回此列表中的元素数。
Spliteratorspliterator()在此列表中的元素上创建一个后期绑定和快速失败的 Spliterator。
Object[]toArray()返回一个数组,该数组以适当的顺序(从第一个元素到最后一个元素)包含此列表中的所有元素。
T[]toArray (T[] a)以适当的顺序(从第一个元素到最后一个元素)返回一个包含此列表中所有元素的数组; 返回数组的运行时类型是指定数组的类型。
  • 从类 java.util.AbstractSequentialList 继承的方法 iterator
  • 从类 java.util.AbstractList 继承的方法 equals, hashCode, listIterator, removeRange, subList
  • 从类 java.util.AbstractCollection 继承的方法 containsAll, isEmpty, removeAll, retainAll, toString
  • 从类 java.lang.Object 继承的方法 finalize, getClass, notify, notifyAll, wait, wait, wait
  • 从接口 java.util.List 继承的方法 containsAll, equals, hashCode, isEmpty, iterator, listIterator, removeAll, retainAll, subList
  • 从接口 java.util.Deque 继承的方法 iterator

LinkedList特有方法

增加

addFirst(E e) addLast(E e)

offer(E e) offerFirst(E e) offerLast(E e)

//创建一个LinkedList集合对象:
LinkedList<String> list = new LinkedList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("b");//LinkedList可以添加重复数据
System.out.println(list); //[a, b, c, b]
list.addFirst("jj");
list.addLast("hh");
System.out.println(list); //[jj, a, b, c, b, hh]
list.offer("kk");//添加元素在尾端
list.offerFirst("pp");
list.offerLast("rr");
删除

poll() pollFirst() pollLast() :JDK1.6新出的方法,提高了代码的健壮性

removeFirst() removeLast()

System.out.println(list); //[pp, jj, a, b, c, b, hh, kk, rr]
System.out.println(list.poll()); //pp 删除头上的元素并且将元素输出
System.out.println(list.pollFirst()); //jj
System.out.println(list.pollLast()); //rr
System.out.println(list.removeFirst()); //a
System.out.println(list.removeLast()); //kk

修改

set (int index, E element)

System.out.println(list.set(3, "a")); //hh
System.out.println(list); //[b, c, b, a]
查看

element()

getFirst() getLast()

indexOf(Object o) lastIndexOf(Object o)

peek() peekFirst() peekLast()

System.out.println(list); //[b, c, b, a]
System.out.println(list.element()); //b
System.out.println(list.getFirst()); //b
System.out.println(list.getLast()); //a
System.out.println(list.indexOf("b")); //0
System.out.println(list.lastIndexOf("b")); //2
System.out.println(list.peek()); //b
System.out.println(list.peekFirst()); //b
System.out.println(list.peekLast()); //a
System.out.println(list); //[b, c, b, a]
遍历
System.out.println("-------普通for循环-------");      
//普通for循环:
for (int i = 0; i < list.size(); i++) {
    System.out.print(list.get(i) + "\t");
}
System.out.println("\n-------增强for-------");
//增强for:
for (String s : list) {
    System.out.print(s + "\t");
}
System.out.println("\n-------迭代器-------");
//迭代器:
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    System.out.print(it.next() + "\t");
}
System.out.println("\n-------强化迭代器-------");
//下面这种方式好,节省内存
for (Iterator<String> it2 = list.iterator(); it2.hasNext(); ) {
    System.out.print(it2.next() + "\t");
}
listIterator

处理迭代器与list不能同时操作问题

public class Listiter {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("aa");
        list.add("bb");
        list.add("cc");
        list.add("dd");
/*        //在"cc"之后添加一个字符串"kk" 出错,原因:就是迭代器和list同时对集合进行操作:
        Iterator<String> it0 = list.iterator();
        while(it0.hasNext()){
            if("cc".equals(it0.next())){
                list.add("kk");
            }
        }*/

        //解决办法:引入新的迭代器:ListIterator,迭代和添加操作都是靠ListIterator来完成的:
        ListIterator<String> it = list.listIterator();
        while(it.hasNext()){
            if("cc".equals(it.next())){
                it.add("kk");
            }
        }
        System.out.println(it.hasNext()); //false,以当前指针位置为准
        System.out.println(it.hasPrevious()); //true
        //逆向遍历:
        System.out.println("------逆向遍历------");
        while(it.hasPrevious()){
            System.out.print(it.previous() + "\t");
        }
        System.out.println(it.hasNext());//true
        System.out.println(it.hasPrevious()); //false
        System.out.println(list); //[aa, bb, cc, kk, dd]
    }
}

相关源码

public class LinkedList<E>{//E是一个泛型,具体的类型要在实例化的时候才会最终确定
        transient int size = 0;//集合中元素的数量
        
        private static class Node<E> {//Node的内部类,节点类
        E item;//当前元素
        Node<E> next;//指向下一个元素地址
        Node<E> prev;//上一个元素地址
        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }
        transient Node<E> first;//链表的首节点
        transient Node<E> last;//链表的尾节点
        
        public LinkedList() {//空构造器:
    }
        
        public boolean add(E e) {//添加元素操作:
        linkLast(e);
        return true;
    }
        void linkLast(E e) {//添加的元素e
        final Node<E> l = last;//将链表中的last节点给l,如果是第一个元素,则l为null
                //将元素封装为一个Node具体的对象:
        final Node<E> newNode = new Node<>(l, e, null);
                //将链表的last节点指向新的创建的对象:
        last = newNode;
                
        if (l == null)//如果添加的是第一个节点
            first = newNode;//将链表的first节点指向为新节点
        else//如果添加的不是第一个节点 
            l.next = newNode;//将l的下一个指向为新的节点
        size++;//集合中元素数量加1操作
        modCount++;
    }
        
        public int size() {//获取集合中元素数量
        return size;
    }
        
        public E get(int index) {//通过索引得到元素:
        checkElementIndex(index);//健壮性考虑
        return node(index).item;
    }
        
    Node<E> node(int index) {
        //如果index在链表的前半段,那么从前往后找
        if (index < (size >> 1)) {
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {//如果index在链表的后半段,那么从后往前找
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }
}
posted @ 2021-08-17 16:41  SKPrimin  阅读(103)  评论(0编辑  收藏  举报