1. Introduction
A linked list is an important data structure in which a linked list contains one or more nodes, and each node has to save its own information as well as the pointer information of the previous node and the next node. Through the table header of the linked list, you can access the entire list of information. The Java API provides a list of Java implementations---linkedlist. LinkedList is the data structure of the linked list through the connection of the node, the speed of inserting or deleting elements into the LinkedList is very fast, and the speed of random access is relatively slow, this is due to the nature of the linked list itself, in the list, each node contains a reference to the previous node, After a node's reference and node storage values, when a new node is inserted, only the relevant front and back relationship node references need to be modified, and the node is deleted as well. The operand only needs to change the link of the node, and the new node can be stored anywhere in the memory, but also because of this linkedlist although there is a get () method, but this method by traversing the node to locate so slow. LinkedList also requires a separate addfrist (), AddLast (), Getfrist (), GetLast (), Removefirst (), Removelast () methods that enable LinkedList to act as a stack, Queues, and dual queues to use. The following is a simple example used by LinkedList:
Package Com.test.collections;import Java.util.linkedlist;public class Linkedlisttest {/** * @param args */public static V OID Main (string[] args) {//TODO auto-generated method stublinkedlist<string> LinkedList = new linkedlist< String> (), Linkedlist.add ("A"), Linkedlist.add ("B"), Linkedlist.add ("C"), Linkedlist.add ("D"), Linkedlist.add ("E "); Linkedlist.add (" F "); Linkedlist.addfirst (" G "); Linkedlist.addlast (" H "); System.out.println (Linkedlist.element ()); System.out.println (Linkedlist.contains ("A")); System.out.println (Linkedlist.element ()); System.out.println (Linkedlist.get (4)); System.out.println (Linkedlist.getfirst ()); System.out.println (Linkedlist.getlast ()); System.out.println (Linkedlist.indexof ("C")); System.out.println (Linkedlist.contains ("D")); System.out.println (Linkedlist.offer ("F")); System.out.println (Linkedlist.isempty ()); System.out.println (Linkedlist.iterator (). Next ()); Linkedlist.push ("N");}}
2. Inheritance structure
LinkedList inherits the Abstractsequentiallist class, realizes the List<e>, Deque<e>, cloneable, serializable these interfaces, The first and last;first of a property with three transient types size,node<e> a pointer to the last node, and finally to the end point. Also need to explain a few of the listedlist of several internal classes, the implementation of the Listiterator interface Listitr class, saving node information nodes class, the implementation of Iterator<e interface Descendingiterator class, Provides a downward iterator implementation. Let's focus on what the node nodes are doing.
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; } }
The item in the nodes node holds the value of the specific object, the next node points to the next node pointer, and prev points to the pointer to the previous node.
3. Specific source code parsing
A: Constructors
Public LinkedList () {} publicly LinkedList (collection<? extends e> c) {this (); AddAll (c); } public boolean addall (collection<? extends e> c) {return AddAll (size, c); } public boolean AddAll (int index, COLLECTION<? extends e> c) {checkpositionindex (index); Object[] A = C.toarray (); int numnew = A.length; if (numnew = = 0) return false; Node<e> pred, SUCC; if (index = = size) {SUCC = null; Pred = Last; } else {SUCC = node (index); pred = Succ.prev; } for (Object o:a) {@SuppressWarnings ("unchecked") e E = (e) o; node<e> NewNode = new Node<> (pred, E, NULL); if (pred = = null) first = NewNode; else Pred.next = NewNode; pred = NewNode; } if (succ = = null) {last = pred; } else { Pred.next = SUCC; Succ.prev = pred; } size + = Numnew; modcount++; return true; }
The first constructor constructs an empty linked list, and the second constructor constructs a linked list that is equivalent to the direct initialization process through the collection. The second process is more complicated, so let's make a simple statement. In fact, the second construction method only need to AddAll () method to understand the name of the concrete implementation of this constructor. The AddAll () method first determines whether the passed-in index is valid, and then transforms the collection into an array of the type of object we need (note the array);
Node<e> pred, succ; if (index = = size) { succ = null; pred = last; } else { SUCC = node (index); pred = Succ.prev; }
This judgment is important, if the size of the index and the list of linked lists can only be placed at the end of the list, this time the tail pointer is assigned to pred; if not equal, the collection can only be inserted in the middle of the list. This is the element that needs to get this node:
node<e> node (int index) { //Assert Iselementindex (index); if (Index < (size >> 1)) { node<e> x = First; for (int i = 0; i < index; i++) x = X.next; return x; } else { node<e> x = last; for (int i = size-1; i > Index; i--) x = X.prev; return x; } }
This method obtains the position of the insertion node and points the previous pointer of the node to our element node pred, and finally begins the process of inserting the array. Iterating through this array not only inserts the values of the array into the position we need, but also keeps updating the size of the linked list.
B:get (int)
Public E get (int index) { checkelementindex (index); Return node (index). Item; } private void Checkelementindex (int index) { if (!iselementindex (index)) throw new Indexoutofboundsexception (outofboundsmsg (index)); }
The method of getting an object of an index is simple to first determine whether the index is out of bounds, and then returns the node and its corresponding value according to the nodes () function.
C:set (Int,e)
Public E Set (int index, E element) { Checkelementindex (index); Node<e> x = node (index); E oldval = X.item; X.item = element; return oldval; }
Resetting the value of a node, the implementation is also very simple, is to first check whether the index is out of bounds, and then more node () function to get the nodes, and then update the value of the node corresponding.
D:add (Int,e)
public void Add (int index, E element) {Checkpositionindex (index); if (index = = size) linklast (element); else Linkbefore (element, node (index)); }private void Checkpositionindex (int index) {if (!ispositionindex (index)) throw new Indexoutofboundsexc Eption (outofboundsmsg (index)); } void Linklast (E e) {final node<e> L = last; Final node<e> NewNode = new node<> (l, E, NULL); last = NewNode; if (L = = null) first = NewNode; else L.next = NewNode; size++; modcount++; } 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++; }
Add a new node in the list of nodes to implement the method: first check the input index is legitimate, and then by the judgment is added to the end of the chain list or the middle of the list, if it is the tail of the call Linklast (E) method, if the middle of the list is to use Linkbefore ( element, node (index), method.
Linklast (E): Insert directly into the tail of the list to modify the pointer at the end of the list, you also need to update the length of the linked list.
Linkbefore (e E, node<e> succ): Inserts a node in front of a non-empty element, and if you insert a head node position you also need to modify the pointer to the head nodes, otherwise you do not need to update the pointer to the head node. Otherwise, you need to modify the previous node of the node at that index to point to the currently inserted element, and make the previous node pointer at the index the currently inserted element. Notice that the length of the linked list was fixed.
E:emove (int)
Public E Remove (int index) { checkelementindex (index); Return unlink (node (index)); } 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; }
Remove the element of a node, first determine whether the index position of the input is legitimate, and then call Unlink (node) method to remove, through the unlink () method of the source code we can see it first get the element at the node and the previous and the next node pointer. If the node is the first node of the linked list, then the head pointer needs to be modified to point to the next point node of the node next, otherwise you just need to modify the previous node of the current node to point to the node's next node. And then if the node is the last element then just modify the tail pointer of the linked list to point to the previous node of the current element, otherwise modify the pointer of a node on the previous node to point to the next pointer to that node, then the node's next pointing node is set to NULL, note the last update of the linked list length.
F:peek ()
Public E Peek () { final node<e> f = first; return (f = = null)? Null:f.item; }
Gets the value of the first linked list node, determines whether it is empty, and returns the corresponding value of the node if it is not empty.
G:element ()
Public E Element () { return GetFirst (); } Public E GetFirst () { final node<e> f = first; if (f = = null) throw new Nosuchelementexception (); return f.item; }
Returns the value of the first node.
H:poll ()
Public E Poll () { final node<e> f = first; return (f = = null)? Null:unlinkfirst (f); } Private E Unlinkfirst (node<e> f) { //assert F = = First && f! = null; Final E element = F.item; Final node<e> next = F.next; F.item = null; F.next = null; Help GC First = next; if (next = = null) last = null; else next.prev = null; size--; modcount++; return element; }
Delete the first node of the list, if the node is not empty call the Unlinkfirst (node) method, do things very simple, delete the first node, garbage collection is to update the list length.
I:remove ()
Public E Remove () { return Removefirst (); } Public E Removefirst () { final node<e> f = first; if (f = = null) throw new Nosuchelementexception (); Return Unlinkfirst (f); }
and the poll () method has a great resemblance to the place
J:offer (E)
Public BooleanOffer (e e) {returnAdd (e); } Public BooleanOfferfirst (e e) {AddFirst (e); return true; } Public BooleanOfferlast (e e) {addlast (e); return true; } Public BooleanAdd (e e) {linklast (e); return true; } voidLinklast (e e) {Finalnode<e> L =Last ; FinalNode<e> NewNode =NewNode<> (L, E,NULL); Last=NewNode; if(L = =NULL) First=NewNode; ElseL.next=NewNode; Size++; Modcount++; } Private voidLinkfirst (e e) {FinalNode<e> f =First ; FinalNode<e> NewNode =NewNode<> (NULL, E, f); First=NewNode; if(f = =NULL) Last=NewNode; ElseF.prev=NewNode; Size++; Modcount++; }
Offer (e) Add elements to the end of the list; Offerfirst (e) Adds elements to the header of the element, and the Offerlast (e) method acts the same as offer (e).
K:push (E)
Public voidpush (e e) {AddFirst (e); } Public voidAddFirst (e e) {Linkfirst (e); } Private voidLinkfirst (e e) {FinalNode<e> f =First ; FinalNode<e> NewNode =NewNode<> (NULL, E, f); First=NewNode; if(f = =NULL) Last=NewNode; ElseF.prev=NewNode; Size++; Modcount++; }
Inserting elements into the head is nothing to say.
L:pop ()
PublicE Pop () {returnRemovefirst (); } PublicE Removefirst () {FinalNode<e> f =First ; if(f = =NULL) Throw Newnosuchelementexception (); returnUnlinkfirst (f); } PrivateE Unlinkfirst (node<e>f) {//assert F = = First && f! = null; FinalE element =F.item; FinalNode<e> next =F.next; F.item=NULL; F.next=NULL;//Help GCFirst =Next; if(Next = =NULL) Last=NULL; ElseNext.prev=NULL; Size--; Modcount++; returnelement; }
The first element is deleted, the head node is also explained before;
4. Other (summary)
ArrayList is a sequential storage table based on linear table, and LinkedList is a list storage table of basic linear table. For new and deleted elements, linkedlist a comparative advantage, only need to change the front and back 2 nodes, and ArrayList to move the data. For random access, ArrayList has the advantage of being able to quickly access according to the index number, while LinkedList needs to traverse the elements of the collection to locate it. For iterative operations (iterate) and lookup operations (INDEXOF), the two are similar. We can think of the need for random access to more of the more appropriate to use ArrayList, if it is inserted and deleted (such as Message Queuing) More then you need to consider linkedlist.
Java Collection of LinkedList source code analysis