1. What is LinkedList

  • AbstractSequentialList bidirectional linked lists can be treated asThe stack,The queueordequeoperate
  • Ordered, non-thread-safe, bidirectional linked lists that use tail insertion by default
  • This parameter is applicable to frequently add or delete scenarios. Select frequently access scenariosArrayList
  • Insert and delete time complexity is O(1), other worst O(n)
  • Due to the implementation of the Deque interface, there are many methods related to the double-endian queue, which will be specifically discussed and not detailed here
  • This release is based on JDK1.7

2. Data structure of LinkedList

  • The class definition
    
  1. public class LinkedList<E>
  2. extends AbstractSequentialList<E>
  3. implements List<E>, Deque<E>, Cloneable, java.io.Serializable
  • AbstractSequentialList can be inherited and operated as a stack, queue, or double-endian queue
  • List interface, can carry out queue operations
  • Implement a Deque interface that uses the LinkedList as a double-ended queue
  • Cloneable interface, rewrite clone() method, can clone
  • Implement java.io.Serializable interface, support serialization
  • Important global variable
    
  1. / * *
  2. * Number of current list elements
  3. * /
  4. transient int size = 0;
  5. / * *
  6. * Pointer to first node.
  7. * Invariant: (first == null && last == null) || (first.prev == null && first.item ! = null)
  8. * List header node
  9. * /
  10. transient Node<E> first;
  11. / * *
  12. * Pointer to last node.
  13. * Invariant: (first == null && last == null) || (last.next == null && last.item ! = null)
  14. * List tail node
  15. * /
  16. transient Node<E> last;
  • The constructor
    
  1. / * *
  2. * Constructs an empty list.
  3. * Default empty constructor -- Note that LinkedList does not provide a constructor for the specified capacity
  4. * /
  5. public LinkedList() {
  6. }
  7. / * *
  8. * Constructs a list containing the elements of the specified
  9. * collection, in the order they are returned by the collection's iterator.
  10. * Support for converting a Collection to a LinkedList
  11. *
  12. * @param c the collection whose elements are to be placed into this list
  13. * @throws NullPointerException if the specified collection is null
  14. * /
  15. public LinkedList(Collection<? extends E> c) {
  16. this();
  17. addAll(c);
  18. }
  • The Node Node
    
  1. / * *
  2. * Store object structure:
  3. * Each Node contains references to the previous Node and the next Node, thus forming a bidirectional linked list
  4. * /
  5. private static class Node<E> {
  6. E item; // Store elements
  7. Node<E> next; // point to the next node
  8. Node<E> prev; // point to the previous node
  9. // The first element is prev, and the second element is the storage element
  10. Node(Node<E> prev, E element, Node<E> next) {
  11. this.item = element;
  12. this.next = next;
  13. this.prev = prev;
  14. }
  15. }

3. LinkedList storage

  • Add method parsing
    
  1. / * *
  2. * Appends the specified element to the end of this list.
  3. * <p>This method is equivalent to {@link #addLast}.
  4. * Insert a new element to the end of the list
  5. * @param e element to be appended to this list
  6. * @return {@code true} (as specified by {@link Collection#add}
  7. * /
  8. public boolean add(E e) {
  9. linkLast(e);
  10. return true;
  11. }
  12. / * *
  13. * Inserts the specified element at the specified position in this list.
  14. * Shifts the element currently at that position (if any) and any
  15. * subsequent elements to the right (adds one to their indices).
  16. * Inserts a new element at the specified subscript position, and all elements greater than that subscript are moved one bit to the right
  17. * @param index index at which the specified element is to be inserted
  18. * @param element element to be inserted
  19. * @throws IndexOutOfBoundsException {@inheritDoc}
  20. * /
  21. public void add(int index, E element) {
  22. checkPositionIndex(index); // subscript boundary check
  23. If (index == size) // Insert tail when subscript == list length
  24. linkLast(element);
  25. else
  26. linkBefore(element, node(index)); // Otherwise, insert front (start position index)
  27. }
  • CheckPositionIndex method resolution
    
  1. private void checkPositionIndex(int index) {
  2. if (! isPositionIndex(index))
  3. throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
  4. }
  5. / * *
  6. * Tells if the argument is the index of a valid position for an iterator or an add operation.
  7. * Determine the bounds of subscripts when iterating or inserting
  8. * /
  9. private boolean isPositionIndex(int index) {
  10. return index >= 0 && index <= size;
  11. }
  • LinkLast method parsing
    
  1. / * *
  2. * Links e as last element.
  3. * Change e to the last element in the list
  4. * /
  5. void linkLast(E e) {
  6. final Node<E> l = last;
  7. final Node<E> newNode = new Node<>(l, e, null); // Note: Next of the new node is null
  8. last = newNode; // Use the new node as the end of the list
  9. // When the end of the queue is null, the list is empty
  10. if (l == null)
  11. first = newNode; // Use the new node as the head of the list
  12. else
  13. l.next = newNode; // Add the next reference to the end node of the original list to the new node
  14. size++; // The current list length is +1
  15. modCount++; // The new operation is a structural change, modCount counts +1
  16. }
  • LinkBefore method parsing
    
  1. / * *
  2. * Inserts element e before non-null Node succ.
  3. * Inserts a new element before the specified non-empty node
  4. * /
  5. void linkBefore(E e, Node<E> succ) {
  6. // assert succ ! = null;
  7. // The logic is basically the same as linkLast except that last is changed to prev and the new node is inserted before the suCC node
  8. final Node<E> pred = succ.prev;
  9. final Node<E> newNode = new Node<>(pred, e, succ);
  10. succ.prev = newNode; // The only difference is that the new node is inserted before the succ node
  11. if (pred == null)
  12. first = newNode;
  13. else
  14. pred.next = newNode;
  15. size++;
  16. modCount++; // Insert is a structural change, modCount counts +1
  17. }
  • If the reader cares, he willlinkBefore()There are no short pointer judgments, but only comment hints, for two reasons


    • CheckPositionIndex (index) : checkPositionIndex(index) : checkPositionIndex(index)IndexOutOfBoundsExceptionTo terminate the method

    • Succ =node(index) succ=node(index) succ=node(index)




4. Read LinkedList

  • Get method parsing
    
  1. / * *
  2. * Returns the element at the specified position in this list.
  3. * Gets the specified subscript element
  4. * @param index index of the element to return
  5. * @return the element at the specified position in this list
  6. * @throws IndexOutOfBoundsException {@inheritDoc}
  7. * /
  8. public E get(int index) {
  9. checkElementIndex(index);
  10. return node(index).item; // Return item instead of node; Node must not be null, and item can be null
  11. }
  • The checkElementIndex method resolves
    
  1. private void checkElementIndex(int index) {
  2. if (! isElementIndex(index))
  3. throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
  4. }
  5. / * *
  6. * Tells if the argument is the index of an existing element.
  7. * To determine whether the current index has an element, see 'linkBefore' for the principle
  8. * Attentive readers may have noticed:
  9. * (get) isElementIndex = index >= 0 && index < size;
  10. * (add) isPositionIndex = index >= 0 && index <= size;
  11. * isPositionIndex =size * isPositionIndex =size * isPositionIndex =size
  12. * From this we can see that:
  13. * Get subscript must be smaller than size, otherwise subscript out of bounds;
  14. * Add (specify elements) :
  15. * When index = size, use tail insertion, because to occupy the subscript size position;
  16. * When index < size, use front insert, because to occupy the index position, and the original position element moved back;
  17. * /
  18. private boolean isElementIndex(int index) {
  19. return index >= 0 && index < size;
  20. }
  • Node method parsing
    
  1. / * *
  2. * Returns the (non-null) Node at the specified element index.
  3. * Returns a non-empty node with the specified subscript
  4. * Node has no verb form, so why not getNode?
  5. * By the way: nodeJs is really good!
  6. * /
  7. Node<E> node(int index) {
  8. // assert isElementIndex(index);
  9. // It is worth mentioning that, in order to improve query efficiency, node queries choose to use binary lookup method
  10. // Personal opinion: But probably because The great God Josh Bloch doesn't think LinkedList is a good place to find, it's just a simple binary
  11. if (index < (size >> 1)) {
  12. Node<E> x = first; // If it's in the front, look from front to back
  13. for (int i = 0; i < index; i++)
  14. x = x.next;
  15. return x;
  16. } else {
  17. Node<E> x = last; // If in the back, go from the back to the front
  18. for (int i = size - 1; i > index; i--)
  19. x = x.prev;
  20. return x;
  21. }
  22. }

5. Remove the LinkedList

  • Remove method parsing
    
  1. / * *
  2. * Retrieves and removes the head (first element) of this list.
  3. * The header node is deleted by default
  4. * @return the head of this list
  5. * @throws NoSuchElementException if this list is empty
  6. * @ since 1.5
  7. * /
  8. public E remove() {
  9. return removeFirst();
  10. }
  11. / * *
  12. * Removes the element at the specified position in this list. Shifts any
  13. * subsequent elements to the left (subtracts one from their indices).
  14. * Returns the element that was removed from the list.
  15. * Deletes elements based on subscripts
  16. * @param index the index of the element to be removed
  17. * @return the element previously at the specified position
  18. * @throws IndexOutOfBoundsException {@inheritDoc}
  19. * /
  20. public E remove(int index) {
  21. checkElementIndex(index); // index >= 0 && index < size
  22. return unlink(node(index)); // Unbind
  23. }
  24. / * *
  25. * Removes the first occurrence of the specified element from this list,if it is present.
  26. * If this list does not contain the element, it is unchanged.
  27. * More formally, removes the element with the lowest index {@code i} such that
  28. * <tt>(o==null? get(i)==null:; o.equals(get(i)))</tt> (if such an element exists).
  29. * Returns {@code true} if this list contained the specified element (or equivalently,
  30. * if this list changed as a result of the call).
  31. * Remove an element directly:
  32. * When the element does not exist, nothing changes
  33. * Returns true if the element existed and was successfully removed, false otherwise
  34. * When there are duplicate elements, only the first occurrence of the same element is deleted:
  35. * For example, remove only the first occurrence of null (i.e., null with the smallest subscript)
  36. * @param o element to be removed from this list, if present
  37. * @return {@code true} if this list contained the specified element
  38. * /
  39. public boolean remove(Object o) {
  40. // Although it is traversal like ArrayList, it is more efficient because there is no need to call the time-consuming 'system. arrayCopy'
  41. if (o == null) {
  42. for (Node<E> x = first; x ! = null; x = x.next) {
  43. if (x.item == null) {
  44. unlink(x);
  45. return true;
  46. }
  47. }
  48. } else {
  49. for (Node<E> x = first; x ! = null; x = x.next) {
  50. if (o.equals(x.item)) {
  51. unlink(x);
  52. return true;
  53. }
  54. }
  55. }
  56. return false;
  57. }
  • Unlink method parsing
    
  1. / * *
  2. * Unlinks non-null node x.
  3. * Unlinking node does three things:
  4. * 1. Unbind the links between the front and back nodes of the current element and rebind the relationship between the front and back nodes
  5. * 2. Clear all attributes of the current element, help GC
  6. * 3. List length -1, modCount count +1(help fail-fast)
  7. * @return returns the element itself. Note that this is item, not node
  8. * /
  9. E unlink(Node<E> x) {
  10. // assert x ! = null;
  11. final E element = x.item;
  12. final Node<E> next = x.next; // The last node
  13. final Node<E> prev = x.prev; // The previous node
  14. // Unbind the first node
  15. If (prev == null) {// The current node is in the head of the list
  16. first = next; // Place the last node at the head of the list
  17. } else {
  18. // Unlinked list header
  19. prev.next = next; // Next points to the next node
  20. x.prev = null; // The first node of the current node clears, help GC
  21. }
  22. // Unbind the last node
  23. If (next == null) {// The current node is at the end of the list
  24. last = prev; // put the previous node at the end of the list
  25. } else {
  26. // Unlinked list tail
  27. next.prev = prev; // Point the prev of the latter node to the former node
  28. x.next = null; // The last node of the current node is cleared, help GC
  29. }
  30. x.item = null; // The current node element is cleared
  31. size--; // The list length is -1
  32. modCount++; // Delete operations are structural changes, modCount counts +1
  33. return element; // Returns the element itself
  34. }
  • UnlinkFirst method parsing
    
  1. / * *
  2. * Unlinks non-null first node f.
  3. * Unbind the head
  4. * /
  5. private E unlinkFirst(Node<E> f) {
  6. // assert f == first && f ! = null;
  7. final E element = f.item;
  8. final Node<E> next = f.next;
  9. f.item = null;
  10. f.next = null; // help GC
  11. first = next; // The next node is the new head node
  12. If (next == null) // The header is already null, then the tail is also null
  13. last = null;
  14. else
  15. next.prev = null; // The prev of the new head node needs to be emptied, non-closed loop
  16. size--;
  17. modCount++;
  18. return element;
  19. }
  • UnlinkLast method parsing
    
  1. / * *
  2. * Unlinks non-null last node l.
  3. * Unbind the tail
  4. * /
  5. private E unlinkLast(Node<E> l) {
  6. // assert l == last && l ! = null;
  7. final E element = l.item;
  8. final Node<E> prev = l.prev;
  9. l.item = null;
  10. l.prev = null; // help GC
  11. last = prev; // The last node is the new tail node
  12. If (prev == null) // If the tail is already null, then the header is also null
  13. first = null;
  14. else
  15. prev.next = null; // Next of the new tail node needs to be emptied, non-closed loop
  16. size--;
  17. modCount++;
  18. return element;
  19. }

6. Collation of other major apis for LinkedList

  • To find the
  • Get the header node:getFirst().peekFirst().peek().element()
  • Get the tail node:getLast().peekLast()

    NoSuchElementException:getFirst()getLast()

    null:peekFirst()peekLast()

    peek()Is equivalent topeekFirst().element()Internally calledgetFirst()
  • insert
  • Head insert:addFirst(E e).offerFirst(E e)
  • Tail insert:addLast(E e).offerLast(E e)

    void:addFirst(E e),addLast(E e).push(E e)

    boolean:add(E e),offer(E e),offerFirst(E e).offerLast(E e)

    linkLast(E e)Is equivalent toadd(E e), most methods are implemented aslinkFirst(E e)linkLast(E e)
  • delete
  • Header deletion:removeFirst().poll().pollFirst().pop()
  • Tail delete:removeLast().pollLast()

    NoSuchElementException:remove(),removeFirst().removeLast().removeLast()

    null:poll(),pollFirst(),pollLast()

    remove()Is equivalent toremoveFirst(), most methods are implemented asunlinkFirst(Node<E> n)unlinkLast(Node<E> n)

    removeLastOccurrence(Object o)remove(Object o)The implementation of almost the same, the difference between the former is reverse order search, the latter is positive order search

7. Stack implementation of LinkedList

  • A Stack is a linear list limited to insert and delete operations at one end
  • According to LIFO, the top is called the top of the stack and the bottom is called the bottom of the stack.
    
  1. / * *
  2. * Simple implementation of the LinkedList version of the queue
  3. * Use first (same principle with last, make sure you only work on one end)
  4. * /
  5. class Stack<T> {
  6. LinkedList<T> linkedList = new LinkedList<T>();
  7. / * *
  8. * into the stack
  9. * /
  10. public void push(T v) {
  11. linkedList.addFirst(v);
  12. }
  13. / * *
  14. * Out of the stack without deleting the top element
  15. * /
  16. public T peek() {
  17. return storage.getFirst();
  18. }
  19. / * *
  20. * Remove the top element from the stack
  21. * /
  22. public T pop() {
  23. return storage.removeFirst();
  24. }
  25. }

8. Queue implementation of LinkedList

  • A Queue is a linear list of limited inserts and deletions at one end
  • According to the first in, first out (FIFO) principle, the end of the table that allows inserts is called Rear, and the end that allows deletions is called Front.
    
  1. / * *
  2. * Simple implementation of the LinkedList version of the queue
  3. * Here we use the end of the queue insert, head delete notation (the reverse principle is the same, as long as the insert and delete are on each end)
  4. * /
  5. class Queue<T> {
  6. LinkedList<T> linkedList = new LinkedList<T>();
  7. / * *
  8. * To join a queue, insert the specified element at the end of the queue
  9. * /
  10. public void offer(T v) {
  11. linkedList.offer(v);
  12. }
  13. / * *
  14. * Gets the header element, but does not delete it, or returns NULL if the queue is empty
  15. * /
  16. public T peek() {
  17. return linkedList.peek();
  18. }
  19. / * *
  20. * Out of the queue, get the header element, but do not delete, if the queue is empty, throw exception
  21. * /
  22. public T element() {
  23. return linkedList.element();
  24. }
  25. / * *
  26. Get the header element and delete it, or return NULL if the queue is empty
  27. * /
  28. public T poll() {
  29. return linkedList.poll();
  30. }
  31. / * *
  32. Get the header element and delete it. If the queue is empty, throw an exception
  33. * /
  34. public T remove() {
  35. return linkedList.remove();
  36. }
  37. }
  • Table of contents


      • COLLECTIONS 7
      • LinkedList is pass
      • ArrayList is pass
      • LinkedHashSet is pass
      • LinkedHashMap are general
      • HashTable is pass
      • HashSet is pass
      • HashMap is pass
      • JAVA 7
      • LinkedList is pass
      • ArrayList is pass
      • LinkedHashSet is pass
      • LinkedHashMap are general
      • HashTable is pass
      • HashSet is pass
      • HashMap is pass
      • Source 7
      • LinkedList is pass
      • ArrayList is pass
      • LinkedHashSet is pass
      • LinkedHashMap are general
      • HashTable is pass
      • HashSet is pass
      • HashMap is pass