// Reprint please indicate the source of the license: http://blog.csdn.net/chdjjby rowandjj2014/8/8 //----------------------------------------------------------
Note: The following source code is based on jdk1.7.0 _ 11
In the previous article, we analyzed the arraylist. Today, let's take a look at the arraylist.
First, the previous frame chart:
The role list also indirectly inherits the abstractlist abstract class. for external users, the Operation interfaces provided by the role list are similar to those provided by arraylist,
The difference lies in internal implementation.. It is a little basic, and The shortlist is
Based on Two-way linked listThis data structure, which has been analyzed in the previous article of arraylist, is implemented through arrays. Based on our previous ideas, we have analyzed the top-down analysis, abstractlist, And the classes or interfaces above. We will not repeat them here. We will start with abstractsequentiallist.
Package Java. util; public abstract class abstractsequentiallist <E> extends abstractlist <E> {protected abstractsequentiallist () {// only one constructor} public e get (INT index) {// obtain the value of the specified position. Try {return listiterator (index ). next (); // via iterator} catch (nosuchelementexception exc) {// throw an exception throw new indexoutofboundsexception ("index:" + index) If no exception is found ); // This is a runtime exception} public e set (INT index, e element) {try {listiterat Or <E> E = listiterator (INDEX); // similarly called listiterator e oldval = E. next (); // Record E. set (element); Return oldval; // return} catch (nosuchelementexception exc) {Throw new indexoutofboundsexception ("index:" + index);} public void add (INT index, E element) {try {listiterator (index ). add (element);} catch (nosuchelementexception exc) {Throw new indexoutofboundsexception ("index:" + index);} public e remove (Int index) {try {listiterator <E> E = listiterator (INDEX); e outcast = E. next (); E. remove (); Return outcast;} catch (nosuchelementexception exc) {Throw new indexoutofboundsexception ("index:" + index); }}// bulk operations public Boolean addall (INT index, collection <? Extends E> C) {try {Boolean modified = false; listiterator <E> e1 = listiterator (INDEX); iterator <? Extends E> E2 = C. iterator (); While (e2.hasnext () {e1.add (e2.next (); modified = true;} return modified;} catch (nosuchelementexception exc) {Throw new indexoutofboundsexception ("Index: "+ index) ;}}// iterators public iterator <E> iterator () {return listiterator ();} public abstract listiterator <E> listiterator (INT index ); // The parameter is the index location. Indicates where to start traversing}It can be found that the methods in this abstract class depend on the listiterator iterator. The method used to obtain the iterator is abstract and left to the subclass for completion. In addition, the iterator method does not return the iterator, the listiterator object is also returned.
Next, we will analyze the detail list. First look at the statement:
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable
Note that the consumer List implements the deque interface, which represents a dual-end queue and encapsulates all operations of the dual-end queue. Therefore
The consumer list can be used as a stack, queue, or dual-end queue.. The following are their member variables:
Transient int size = 0; // set size (number of nodes) transient node <E> first; // header pointer transient node <E> last; // tail pointer
As mentioned above, the linked list is implemented through a two-way linked list, so there is no need for resizing because nodes are dynamically applied. The node type is node. See the node source code below:
Private Static class node <E> {e item; // data node <E> next; // subsequent pointer node <E> Prev; // The precursor pointer node (node <E> Prev, e element, node <E> next) {This. item = element; this. next = next; this. prev = Prev ;}}Obviously
Node structure of two-way linked list. Let's look at the javaslist constructor again:
public LinkedList() {} public LinkedList(Collection<? extends E> c) { this(); addAll(c); }Let's look at some operation methods on the node: If you are familiar with two-way linked list, you will find the following functions are very simple, nothing more than dealing with pointer pointing problems.
Private void linkfirst (E) {// insert it to the final node in the header <E> F = first; // create a new node. The precursor is empty, followed by F (that is, the current header node) final node <E> newnode = new node <> (null, E, F ); // note that this generic writing method can also be first = newnode; // the header Pointer Points to the new node if (F = NULL) // when the linked list is empty, last = newnode; // The tail Pointer Points to the new node else // otherwise, F. prev = newnode; // point the forward of F to the new node size ++; modcount ++;} void linklast (E) {// Insert the final node to the end <E> L = last; // record the final node of the Temporary Variable <E> newnode = new node <> (L, E, null ); // Create a new node. The precursor is l last = newnode; // update the tail pointer if (L = NULL) // If the linked list is empty first = newnode; else l. next = newnode; size ++; modcount ++; // used for fast failure mechanism} void linkbefore (E, node <E> succ) {// before inserting e into succ // assert succ! = NULL; // The caller must ensure that succ is not empty. Final node <E> Pred = succ. prev; // record the succ precursor final node <E> newnode = new node <> (Pred, E, succ); // the precursor of the new node points to the succ precursor, the successor of the new node points to succ. prev = newnode; // The succ precursor points to the new node if (PRED = NULL) // succ is the first node first = newnode; // you can change the header pointer else Pred. next = newnode; // otherwise, the successor of the succ should point to the new node size ++; modcount ++;} private e unlinkfirst (node <E> F) {// dry turn node 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; // change the header pointer if (next = NULL) Last = NULL; else next. prev = NULL; size --; modcount ++; return element;} private e unlinklast (node <E> L) {// end node l // assert L = last & L! = NULL; Final e element = L. item; final node <E> Prev = L. prev; L. item = NULL; L. prev = NULL; // help GC last = Prev; If (prev = NULL) First = NULL; else Prev. next = NULL; size --; modcount ++; return element;} e unlink (node <E> X) {// kill a common node x // assert X! = NULL; Final e element = x. item; // record the node value final node <E> next = x. next; // record the next node final node <E> Prev = x. prev; // record the previous node if (prev = NULL) {// The previous node is empty first = next;} else {Prev. next = next; // next of the previous node points to the next node X. prev = NULL;} If (next = NULL) {last = Prev;} else {next. prev = Prev; // the previous one of the next node points to the previous x. next = NULL;} X. item = NULL; size --; modcount ++; return element ;}With these basic functions, it is convenient to implement other operations. For example:
public void addFirst(E e) { linkFirst(e); } public void addLast(E e) { linkLast(e); } public boolean add(E e) { linkLast(e); return true; }Let's look at the Remove Method again:
public boolean remove(Object o) { if (o == null) { for (Node<E> x = first; x != null; x = x.next) { if (x.item == null) { unlink(x); return true; } } } else { for (Node<E> x = first; x != null; x = x.next) { if (o.equals(x.item)) { unlink(x); return true; } } } return false; }
Similar to arraylist, arraylist performs two processing operations based on whether the parameter is null,
It indicates that the writable list also supports null elements..
Let's look at the clear operation:
Public void clear () {for (node <E> X = first; X! = NULL;) {node <E> next = x. next; // The next X. item = NULL; X. next = NULL; X. prev = NULL; X = next;} First = last = NULL; size = 0; modcount ++ ;}The following function encapsulates the operations on the index linked list position:
Node <E> node (INT index) {// assert iselementindex (INDEX); If (index <(size> 1 )) {// determine the approximate location of the node to be indexed <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 function uses a small trick to first determine whether the index is located in the first half or the second half of the linked list. If it is located in the first half of the list, it will be indexed sequentially, otherwise, index in reverse order (this is one of the advantages of a two-way linked list ).Methods not implemented in abstractsequentiallist are implemented here:
public ListIterator<E> listIterator(int index) { checkPositionIndex(index); return new ListItr(index); }
This listitr is an internal class of the consumer list and implements the listiterator interface.
private class ListItr implements ListIterator<E> private Node<E> next; ListItr(int index) { // assert isPositionIndex(index); next = (index == size) ? null : node(index); nextIndex = index; }
Specify the position of the Start traversal through the constructor,
Internally, you can call the Node Method to index the objects at this position.. The specific method is not described in length. It is worth mentioning that this class also provides a reverse iterator:
public Iterator<E> descendingIterator() { return new DescendingIterator(); }
This reverse iterator is actually an encapsulation of the listitr described above.
Summary:
1. The external list is implemented through a two-way linked list;
2. The rule list supports the null element;
3. The partition list is easier to insert and delete elements, but the search operation is time-consuming (compared with the arraylist), although it is internally optimized (select the order by location or reverse traversal );
4. The iterator list also implements the iterator in the form of internal classes (only listiterator is implemented, and the iterator method returns the listiterator object ).
5. Consumer List implements the deque interface, which can be used as a stack, queue, and dual-end queue.