一.继承结构图
与Arraylist相比,没有实现randomAccess接口。但它实现了deque接口,底层就是数据结构中的链表
并且不是直接继承Abstractlist类,而是继承AbstractSequentialList类(这样它就不支持随机访问)
二.基本介绍
LinkedList是一个实现了list接口和Deque接口的双端链表
linkedlist不是线程安全的,如果想使得linkedlist变成线程安全的,可以使用collections类的synchronizedList方法去包装linkedlist对象
List list=Collections.synchronizedList(new LinkedList(...));
三.总结
1.linkedList获得头节点有哪些方法?获得头节点有哪些方法?
getFirst(),element(),peek(),peekFirst().其中getFirst和element在链表为空时会抛出nosuchElementException异常
而peek和peekfirst方法返回null(这两个方法的实现时完全一样的)
获得尾节点有peeklast()和getlast()方法,区别也是peeklast在链表为空时会返回null而不会报错
2.添加节点方法?
addfirst() addlast() offer() offerfirst() offerlast(),push()其中offer其实就是调用了addlast,push就是调用了addfirst
offerfirst和offerlast与前两者的区别就是这两个方法返回true,前两个方法返回void
扫描二维码关注公众号,回复:
1633575 查看本文章
3.删除节点的方法?
remove() removefirst() pop() poll() pollfirst() polllast()其中remove()和pop()其实就是调用了removefirst(),所以在链表为空时会抛出nosuchElementException
后面三个会在链表为空时返回null,不会抛出异常
4.由于Linkedlist是一个实现了Deque的的双端队列,多以linkedlist既可以当作queue又可以当作stack,用linkedList实现栈?
public class LinkedListStack<E>{ private LinkedList<E> linkedList; public LinkedListStack(){ linkedList = new LinkedList<E>(); } //压入数据 public void push(E e){ linkedList.push(e); } //弹出数据 public E pop(){ //在链表为空时会报异常 return linkedList.pop(); //在链表为空时返回null //return linkedList.poll(); } //检索栈顶数据(不弹出) public E peek(){ return linkedList.peek(); } }
public class LinkedListQueue<E> { private LinkedList<E> linkedList; public LinkedListQueue(){ linkedList = new LinkedList<E>(); } //入队 public void enQueue(E e){ linkedList.addLast(e); } //出队 public void deQueue(){ //队列为空时抛出异常,等价于linkedList.removeFirst(); linkedList.pop(); //不会抛出异常 //linkedList.poll(); } //打印队列 public void allItem(){ Iterator<E> iterator = linkedList.iterator(); if(iterator.hasNext()){ System.out.println(iterator.next()); } } public static void main(String[] args) { LinkedListQueue<Integer> queue = new LinkedListQueue<>(); queue.enQueue(1); queue.enQueue(2); queue.deQueue(); queue.allItem(); } }
四.源码阅读
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable { //当前链表中数据个数 transient int size = 0; //linkedlist是双端链表结构,first指向链表头部,last指向链表尾部 transient Node<E> first; transient Node<E> last; //两个构造函数,一个用于构造空链表,另一个用已有的集合创建链表 public LinkedList() { } public LinkedList(Collection<? extends E> c) { this(); addAll(c); } //Node节点,存储节点的数据,前一个节点和后一个节点的引用 private static class Node<E> { 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; } } //添加元素在链表尾部 public boolean add(E e) { linkLast(e); return true; } //添加元素到指定位置 public void add(int index, E element) { checkPositionIndex(index); if (index == size) linkLast(element); else linkBefore(element, node(index)); } void linkBefore(E e, Node<E> succ) { // assert succ != null; final Node<E> pred = succ.prev; final Node<E> newNode = new Node<>(pred, e, succ); succ.prev = newNode; if (pred == null) first = newNode; else pred.next = newNode; size++; modCount++; } //由于实现了deque接口,所以还有一系列添加节点的方法 addFirst(E e)方法 addLast(E e)方法 //offerfirst与addfirst的区别是该方法可以返回特定的返回值,addfirst返回void public boolean offerFirst(E e) { //调用addfirst addFirst(e); return true; } offerLast(E e)方法(与addlast区别同上) //获取某位置的元素 public E get(int index) { //检查边界 checkElementIndex(index); return node(index).item; } //获得位置为0的头节点数据 (主要方法有:getfirst,element,peek,peekfirst) public E getFirst() { final Node<E> f = first; if (f == null) //会在链表为空时抛出nosuchElementException异常 throw new NoSuchElementException(); return f.item; } public E element() { return getFirst(); } //peek和peekfirst会在链表为空时返回null而不会抛出异常 public E peek() { final Node<E> f = first; return (f == null) ? null : f.item; } public E peekFirst() { final Node<E> f = first; return (f == null) ? null : f.item; } //获得位置size-1的尾节点数据 public E getLast() { final Node<E> l = last; if (l == null) throw new NoSuchElementException(); return l.item; } public E peekLast() { final Node<E> l = last; return (l == null) ? null : l.item; } //返回第一个匹配的索引(可以看出linkedlist可以包含null元素) public int indexOf(Object o) { int index = 0; if (o == null) { //从头往后遍历 for (Node<E> x = first; x != null; x = x.next) { if (x.item == null) return index; index++; } } else { //从头往后遍历 for (Node<E> x = first; x != null; x = x.next) { if (o.equals(x.item)) return index; index++; } } return -1; } //返回最后一个匹配的索引 public int lastIndexOf(Object o) { int index = size; if (o == null) { //从后向前遍历 for (Node<E> x = last; x != null; x = x.prev) { index--; if (x.item == null) return index; } } else { //从后向前遍历 for (Node<E> x = last; x != null; x = x.prev) { index--; if (o.equals(x.item)) return index; } } return -1; } //检查链表是否包含了某个元素(实际上时调用了indexof方法) public boolean contains(Object o) { return indexOf(o) != -1; } //删除某个对象(从前向后遍历,找到该元素后调用unlick方法) public boolean remove(Object o) { //如果删除对象为null if (o == null) { //从前向后遍历 for (Node<E> x = first; x != null; x = x.next) { //一旦匹配,调用unlink()方法和返回true if (x.item == null) { unlink(x); return true; } } } else { //从前向后遍历 for (Node<E> x = first; x != null; x = x.next) { //一旦匹配,调用unlink()方法和返回true if (o.equals(x.item)) { unlink(x); return true; } } } return false; } E unlink(Node<E> x) { // assert x != null; final E element = x.item; final Node<E> next = x.next;//得到后继节点 final Node<E> prev = x.prev;//得到前驱节点 //删除前驱指针 if (prev == null) { first = next;如果删除的节点是头节点,令头节点指向该节点的后继节点 } else { prev.next = next;//将前驱节点的后继节点指向后继节点 x.prev = null; } //删除后继指针 if (next == null) { last = prev;//如果删除的节点是尾节点,令尾节点指向该节点的前驱节点 } else { next.prev = prev; x.next = null; } x.item = null; size--; modCount++; return element; } E unlink(Node<E> x) { // assert x != null; final E element = x.item; final Node<E> next = x.next;//得到后继节点 final Node<E> prev = x.prev;//得到前驱节点 //删除前驱指针 if (prev == null) { first = next;如果删除的节点是头节点,令头节点指向该节点的后继节点 } else { prev.next = next;//将前驱节点的后继节点指向后继节点 x.prev = null; } //删除后继指针 if (next == null) { last = prev;//如果删除的节点是尾节点,令尾节点指向该节点的前驱节点 } else { next.prev = prev; x.next = null; } x.item = null; size--; modCount++; return element; } E unlink(Node<E> x) { // assert x != null; final E element = x.item; final Node<E> next = x.next;//得到后继节点 final Node<E> prev = x.prev;//得到前驱节点 //删除前驱指针 if (prev == null) { first = next;如果删除的节点是头节点,令头节点指向该节点的后继节点 } else { prev.next = next;//将前驱节点的后继节点指向后继节点 x.prev = null; } //删除后继指针 if (next == null) { last = prev;//如果删除的节点是尾节点,令尾节点指向该节点的前驱节点 } else { next.prev = prev; x.next = null; } x.item = null; size--; modCount++; return element; } E unlink(Node<E> x) { // assert x != null; final E element = x.item; final Node<E> next = x.next;//得到后继节点 final Node<E> prev = x.prev;//得到前驱节点 //删除前驱指针 if (prev == null) { first = next;如果删除的节点是头节点,令头节点指向该节点的后继节点 } else { prev.next = next;//将前驱节点的后继节点指向后继节点 x.prev = null; } //删除后继指针 if (next == null) { last = prev;//如果删除的节点是尾节点,令尾节点指向该节点的前驱节点 } else { next.prev = prev; x.next = null; } x.item = null; size--; modCount++; return element; }