The previous study of the source of ArrayList,
Array is sequential storage structure, storage interval is continuous, occupy memory is serious, so the space is very complex.
But the array of binary lookup time complexity is small, for O (1), the array is characterized by easy addressing, insertion and removal difficulties.
Today to learn another common data structure linkedlist implementation,
LinkedList use a linked list as a storage structure, the list is a linear storage structure, in memory is not a continuous space,
Occupy memory is relatively loose, so space complexity is very small, but time complexity is very large, up to O (N), linked list is difficult to address, insert and delete easy.
All the code is based on JDK 1.6.
>> about LinkedList
LinkedList inherits the Abstractsequentiallist, realizes the List,deque,cloneable,serializable interface,
(1) Inheritance and implementation
Inherits the Abstractsequentiallist class, provides the related addition, the deletion, the modification, the traversal and so on function.
The implementation of the list interface, provides related additions, deletions, modifications, traversal and other functions.
Implement the Deque interface, which can use LinkedList as a double-ended queue, can be used as a queue or stack
Implements the Cloneable interface, which covers the function clone (), can be cloned copy,
Implement Java.io.Serializable interface, LinkedList support serialization, can be transmitted by serialization.
(2) Thread safety
LinkedList is non-synchronous, that is, thread is unsafe, and if more than one thread accesses LinkedList at the same time, a Concurrentmodificationexception exception may be thrown.
final void Checkforcomodification () { if (modcount! = expectedmodcount) throw new Concurrentmodificationexception () ;}
In the code, Modcount records the number of times the LINKEDLIST structure has been modified. Iterator when initialized, Expectedmodcount=modcount. Any behavior that modifies the LinkedList structure through iterator will update both Expectedmodcount and Modcount, making the two values equal. The method of modifying its structure by LinkedList objects only updates modcount. So suppose there are two threads A and B. A iterator iterates through and modifies the LinkedList, and B, at the same time, modifies its structure through the object, then the iterator method throws an exception
>> doubly linked list structure
Unlike regular lists, each node of a doubly linked list maintains not only the next pointer to the next node, but also the previous pointer to the previous node.
(1) Internal implementation
The LinkedList internally uses entry<e> to encapsulate the two-way cyclic link table nodes.
Definition of LinkedList head node:
The definition of the head node private transient entry<e> header = new entry<e> (null, NULL, NULL);//The actual length of the list is private transient int size = 0;
Entry is a static inner class,
private static class Entry<e> {E element; Entry<e> Next; Entry<e> previous; Entry (E element, entry<e> Next, entry<e> previous) { this.element = element; This.next = Next; This.previous = previous;} }
(2) Constructors
Two constructors are provided inside the LinkedList,
/** * Initializes an empty list, which can be understood as a two-way loop linked list * /Public LinkedList () { Header.next = header.previous = header; } /** * Constructs a list */public LinkedList (collection<? extends e> c) using the specified Collection {this (); AddAll (c); }
>> Common Methods
(1) Traversal mode
LinkedList supports multiple traversal methods. It is recommended that you do not use random access to traverse LinkedList, but in a way that is traversed one by one.
(01) The first, traversed by an iterator . That is, through the iterator to traverse.
for (Iterator iter = List.iterator (); Iter.hasnext ();) iter.next ();
(02) Traverse LinkedList with fast random access
int size = List.size (); for (int i=0; i<size; i++) { list.get (i); }
(03) Traversing LinkedList through another for loop
for (Integer integ:list) ;
(04) through Pollfirst () to traverse the LinkedList
while (list.pollfirst () = null) ;
(05) through Polllast () to traverse the LinkedList
while (list.polllast () = null) ;
(06) through Removefirst () to traverse the LinkedList
try { while (list.removefirst () = null) ;} catch (Nosuchelementexception e) {}
(07) through removelast () to traverse the LinkedList
try { while (list.removelast () = null) ;} catch (Nosuchelementexception e) {}
the code to test the efficiency of these traversal methods is as follows :
1 Import java.util.List; 2 Import Java.util.Iterator; 3 Import java.util.LinkedList; 4 Import java.util.NoSuchElementException; 5 6/* 7 * @desc test several traversal modes and efficiency of LinkedList 8 * 9 * @author Skywang */One public class Linkedlistthrutest {12 public static void Main (string[] args) {13//traversal through iterator LinkedList iteratorlinkedlistthruiterator (g Etlinkedlist ()); 15 16//Traverse LinkedList Iteratorlinkedlistthruforeach (Getlinkedlist ()) by fast random access; 18 19//through the variant of the For loop to access the Traverse LinkedList IteratorThroughFor2 (Getlinkedlist ()); 21 22//Through Pollfirst () Traverse LinkedList Iteratorthroughpollfirst (Getlinkedlist ()); 24 25//through Polllast () Traverse LinkedList-Iteratorthroughpolllast (Getlinkedlist ()); 27 28//Through Removefirst () Traverse LinkedList Iteratorthroughremovefirst (Getlinkedlist ()); 30 31//Through Removelast () Traverse LinkedList iteratorthroughremovelast (Getlinkedlist ()); 33 } The private static LinkedList getlinkedlist () {LinkedList llist = new LinkedList (); 37 for (int i=0; i<100000; i++) llist.addlast (i); Llist return; 41} 42/** 43 * Traverse LinkedList with a fast iterator * */private static void Iteratorlinkedlistthruiterator (Link Edlist<integer> list) {if (list = = null) * return; 48 49//Record start time Lon G start = System.currenttimemillis (); Wuyi for (Iterator iter = List.iterator (); Iter.hasnext ();) Iter.next (); 54 55//Record end time: a long end = System.currenttimemillis (); Interval long = End-start; System.out.println ("Iteratorlinkedlistthruiterator:" + interval+ "MS"); 59} 60 61/** 62 * Traverse LinkedList through fast random access * * * * * private static void Iteratorlinkedlistthruforeach (linkedlist<integer> list) {$ if (list = = null) 66 return; 67 68//Record start time, long start = System.currenttimemillis (); the int size = List.size (); i<size; for (int i=0; i++) {list.get (i); 74} 75//Record end time Long end = System.currenttimemillis (); Interval long = End-start; System.out.println ("Iteratorlinkedlistthruforeach:" + interval+ "MS"); 79} 80 81/** 82 * Through a different for loop to traverse the LinkedList. */The private static void IteratorThroughFor2 (Linke Dlist<integer> list) {if (list = null) + return; 87 88//Record start time Start = System.currenttimemillis (); 92 for (Integer integ:list); 93 94//Record End time: Long end = System.currenttimemillis (); Interval long = End-start; System.out.println ("IteratorThroughFor2:" + interval+ "MS"); 98} 99 100/**101 * via PollfirsT () to traverse LinkedList102 */103 private static void Iteratorthroughpollfirst (Linkedlist<integer> list) {104 if (list = = null), 106 107//Record start time 108 long start = System.currenttimemillis (); 1 List.pollfirst () = null) 110; 111 112//Record end time 113 long end = System.currentt Imemillis (); Long interval = end-start;115 System.out.println ("Iteratorthroughpollfirst:" + interval+ "MS"); 116}117 118/**119 * Traverse LinkedList120 */121 private static void iteratorthroughp via Polllast () Olllast (linkedlist<integer> list) {122 if (list = = null) 123 return; 124 125//Record start time 126 Long start = System.currenttimemillis (); 127 while (list.polllast () = null) 128; 129 130 Record end time 131 long end = System.currenttimemillis (); Long interval = end-start;133 System.ou T.println ("IteratorthrouGhpolllast: "+ interval+" MS "), 134}135 136/**137 * through Removefirst () to traverse LinkedList138 */139 private S tatic void Iteratorthroughremovefirst (linkedlist<integer> list) {if (list = = null) 141 return ; 142 143//Record start time 144 long start = System.currenttimemillis (); 145 try {146 while (list . Removefirst () = null) 147; 148} catch (Nosuchelementexception e) {149}150 151/ /record end time Long end = System.currenttimemillis (); 153 long interval = end-start;154 SYSTEM.OUT.P Rintln ("Iteratorthroughremovefirst:" + interval+ "MS"), 155}156 157/**158 * via Removelast () to traverse LinkedList159 */160 private static void Iteratorthroughremovelast (Linkedlist<integer> list) {161 if (list = = null) 162 return; 163 164//Record start time 165 long start = System.currenttimemillis (); 166 try {167 while (LIST.REmovelast () = null) 168; 169} catch (Nosuchelementexception e) {170}171 172//Record Recording end time 173 long end = System.currenttimemillis (); 174 long interval = end-start;175 System.out.prin TLN ("Iteratorthroughremovelast:" + interval+ "MS"); 176}177 178}
Execution Result :
Iteratorlinkedlistthruiterator:8 msiteratorlinkedlistthruforeach:3724 Msiteratorthroughfor2:5 Msiteratorthroughpollfirst:8 Msiteratorthroughpolllast:6 Msiteratorthroughremovefirst:2 Msiteratorthroughremovelast:2 ms
Using Removefist () or Removelast () is the most efficient when traversing linkedlist. However, when they are traversed, the original data is deleted and the 3rd traversal method should be used if it is simply read and not deleted.
In any case, do not traverse linkedlist! by random access.
(2) Common methods (from the API)
Boolean Add (E E)
Adds the specified element to the end of this list.
void Add (int index, E Element)
Inserts the specified element in the location specified in this list.
Boolean AddAll (collection<? extends e> c)
Adds all the elements in the specified collection to the end of this list, in order to specify the order in which the collection iterators return the elements.
Boolean addall (int index, COLLECTION<? extends e> c)
Inserts all the elements in the specified collection from the specified position at the beginning of the list.
void AddFirst (e e)
Inserts the specified element at the beginning of this list.
void AddLast (e e)
Adds the specified element to the end of this list.
void Clear ()
Removes all elements from this list.
Object Clone ()
Returns a shallow copy of this linkedlist.
Boolean contains (Object o)
Returns true if this list contains the specified element.
Iterator<e> Descendingiterator ()
Returns an iterator that iterates over the elements of this double-ended queue in reverse order.
E Element ()
Gets the header (first element) of this list without removing it.
E get (int index)
Returns the element at the specified position in this list.
E GetFirst ()
Returns the first element of this list.
E GetLast ()
Returns the last element of this list.
int indexOf (Object o)
Returns the index of the specified element that first appears in this list, or 1 if the element is not included in this list.
int lastIndexOf (Object o)
Returns the index of the last occurrence of the specified element in this list, or 1 if the element is not included in this list.
listiterator<e> listiterator (int index)
Returns a list iterator (in the appropriate order) for the elements in this list, starting at the specified position in the list.
Boolean offer (E e)
Adds the specified element to the end of this list (the last element).
Boolean Offerfirst (E e)
Inserts the specified element at the beginning of this list.
Boolean offerlast (E e)
Inserts the specified element at the end of this list.
E-Peek ()
Gets the header (first element) of this list without removing it.
E Peekfirst ()
Gets but does not remove the first element of this list, or null if the list is empty.
E Peeklast ()
Gets but does not remove the last element of this list, or null if the list is empty.
E Poll ()
Gets and removes the header of this list (first element)
E Pollfirst ()
Gets and removes the first element of this list, or returns null if the list is empty.
E Polllast ()
Gets and removes the last element of this list, or returns null if the list is empty.
E pop ()
POPs an element at the stack represented by this list.
void push (E e)
Pushes an element into the stack represented by this list.
E Remove ()
Gets and removes the header of this list (the first element).
E Remove (int index)
Removes the element at the specified position in this list.
Boolean remove (Object o)
Removes the first occurrence of the specified element (if present) from this list.
E Removefirst ()
Removes and returns the first element of this list.
Boolean removefirstoccurrence (Object o)
Removes the first occurrence of the specified element from this list (when traversing the list from head to tail).
E Removelast ()
Removes and returns the last element of this list.
Boolean removelastoccurrence (Object o)
Removes the last occurrence of the specified element from this list (when traversing the list from head to tail).
e Set (int index, e Element)
Replaces the element at the specified position in this list with the specified element.
int size ()
Returns the number of elements in this list.
>> Dual-ended queues
A double-ended queue is a data structure that restricts insert and delete operations, with the nature of queues and stacks,
A double-ended queue is a multi-purpose data structure compared to a stack or queue, and in a container class library, a double-ended queue is sometimes used to provide both stack and queue functions.
Viewing the implementation of the source code, you can find the relevant methods as queues and stacks.
(1) Use as a queue
Add (e) Internal implementation is addlast (e)
Offer (e) queue, return directly to add ()
Remove () Gets and removes the first element of the list, same as poll (), and internally calls Removefirst ()
Poll () out team gets and removes team header elements the internal implementation is called Removefirst ()
Element () returns the first element of the list without removing it, internally calling GetFirst ()
Peek () returns the first element of the list but does not remove it, and element () is the same, internally called GetFirst ()
(2) use as a stack
Push (e) into the stack is AddFirst (e)
Pop () out of stack i.e. Removefirst ()
Peek () gets the top element of the stack without removing the peekfirst ()
>> Source Analysis
(1) Major node update operations
The two private methods in the source Addbefore and remove are the main operations that maintain the update of the nodes,
This part is mainly the data structure in the operation of the linked list, it is relatively simple to understand,
Most of the add, Remode, and other operations can be implemented by both methods.
/** * Insert a new node element before the incoming node * /private entry<e> Addbefore (e E, entry<e> Entry) { // Constructs a new node entry<e> newEntry = new Entry<e> (E, Entry, entry.previous);//Adjust the node of the new node before and after the point newEntry.previous.next = newentry;newentry.next.previous = Newentry;size++;modcount++;return newEntry; } /** * Delete this node in the linked list * /private E Remove (entry<e> e) { //e equals the empty node at initialization, throws an exception if (E = = header) throw New Nosuchelementexception (); E result = e.element; /** * The delete operation is to adjust the point of the front and back node pointer, bypassing the incoming nodes * and then the forward and backward pointers and value of the incoming node are set to null */e.previous.next = E.next; e.next.previous = e.previous; E.next = e.previous = null; E.element = null;size--;modcount++; return result; }
(2) The list iterator is implemented through the LISTITR inner class
Private class Listitr implements listiterator<e> {private entry<e> lastreturned = Header;private entry<e& Gt next;private int nextindex;private int expectedmodcount = Modcount; LISTITR (int index) {if (Index < 0 | | index > size) throw new Indexoutofboundsexception ("Index:" +index+ ", Siz E: "+size"); if (Index < (size >> 1)) {next = Header.next;for (nextindex=0; nextindex<index; nextindex++) next = Next.ne xt } else {next = Header;for (nextindex=size; nextindex>index; nextindex--) next = next.previous; }}public Boolean hasnext () {return nextindex! = size;} Public E Next () {checkforcomodification (); if (Nextindex = = size) throw new nosuchelementexception (); lastreturned = Next; Next = Next.next; nextindex++; return lastreturned.element;} public Boolean hasprevious () {return nextindex! = 0;} Public E Previous () {if (Nextindex = = 0) throw new nosuchelementexception (); lastreturned = next = next.previous; nextindex--; Checkforcomodification (); return lastreturned.element;} public int Nextindex () {return nextindex;} public int Previousindex () {return nextIndex-1;} public void Remove () {checkforcomodification (); entry<e> lastnext = Lastreturned.next; try {LinkedList.this.remove (lastreturned); } catch (Nosuchelementexception e) {throw new illegalstateexception (); } if (next==lastreturned) next = Lastnext; elsenextindex--; lastreturned = header; expectedmodcount++;} public void Set (E e) {if (lastreturned = = header) throw new IllegalStateException (); Checkforcomodification (); Lastreturned.element = e;} public void Add (e e) {checkforcomodification (); lastreturned = header; Addbefore (E, next); nextindex++; expectedmodcount++;} final void Checkforcomodification () {if (Modcount! = expectedmodcount) throw new ConcurrentmodificationeXception ();} }
>>fail-fast mechanism
Fail-fast, fast failure is an error detection mechanism for Java collections.
The fail-fast mechanism is likely to occur when multiple threads are manipulating a collection for structural changes.
Remember that it is possible, not necessarily. For example: Suppose there are two threads (thread 1, thread 2), thread 1 through iterator in the elements of the collection A, at some point, thread 2 modifies the structure of collection A (is the structure of the changes above, rather than simply modify the contents of the collection elements), then this time the program will throw Concurrentmodificationexception anomalies, resulting in a fail-fast mechanism.
the difference between >>arraylist and LinkedList
ArrayList is an array-based structure in which the nodes have no special connection to each other, the default size is 10, and the maximum size is integer.max_value-8.
When the size is not enough to automatically grow, it can be directly through the Get,set to obtain, modify a node data.
LinkedList is a doubly linked list-based structure, with each node having two pointers pointing to the previous node and the next node, respectively. It is variable-length.
The difference between the two implementation classes is that the ArrayList get ()/set () is more efficient than LinkedList, and the LinkedList Add ()/remove () is more efficient than ArrayList.
Specifically: the array to request a contiguous amount of memory space, is in the compilation period to determine the size of the runtime is not dynamic change, but why ArrayList can change the size of it,
Because at add, if it exceeds the set size, it creates a new larger (growth rate appears to be 0.5) ArrayList,
Then copy the original list to the new list and point the address to the new list, and the old list is recycled by GC, which is obviously very memory-intensive and very inefficient.
But because the memory space it applies for is continuous, it can be directly subscript to obtain the required data, the time complexity is O (1), and the list is O (n),
The list structure is not the same, it can dynamically request memory space. The pointer to the previous node of the node that needs to be joined is untied and points to the new plus node, and the new node pointer points to the next node. It's very fast.
So say ArrayList suitable for query, LinkedList suitable to delete.
Refer to the Java Collection series 05 LinkedList detailed introduction (source parsing) and usage examples
Java Collection Source learning Note (iii) LinkedList analysis