Java collection (b): List of lists

Source: Internet
Author: User
Tags addall prev set set java se

In the previous section, the overall situation of the Java collection is described. Starting with this section, you'll learn about the detailed classes. This is not just about how classes are used. You will also try to analyze the implementation of the class from the source code perspective. This section describes the list interface and the implementation class. That is, the list of linked lists LinkedList and array list ArrayList.

1 list interfaces and abstract classes

The list interface extends from the collection interface, which designs a number of methods suitable for listing operations. List is an ordered set. Elements can be added to a specific location in the container.

After compiling the List.java source code with JAVAC, you can use JAVAP to decompile the source code to get the details of the interface. For example, the following is the result of the call:

Compiled from ' List.java ' public interface java.util.list<e> extends java.util.collection<e> {public  abstract int size ();  Public abstract Boolean isEmpty ();  Public abstract Boolean contains (Java.lang.Object);  Public abstract java.util.iterator<e> Iterator ();  Public abstract java.lang.object[] ToArray ();  Public abstract <T> t[] ToArray (t[]);  Public abstract Boolean Add (E);  Public abstract Boolean remove (Java.lang.Object);  Public abstract Boolean Containsall (java.util.collection<?>);  Public abstract Boolean AddAll (java.util.collection<? extends e>);  Public abstract Boolean AddAll (int, java.util.collection<? extends e>);  Public abstract Boolean RemoveAll (java.util.collection<?>);  Public abstract Boolean Retainall (java.util.collection<?>);  public void ReplaceAll (java.util.function.unaryoperator<e>);  public void sort (java.util.comparator<? super e>);  public abstract void Clear (); Public abstract Boolean equalS (java.lang.Object);  public abstract int hashcode ();  Public abstract E get (int);  Public abstract e Set (int, e);  public abstract void Add (int, E);  Public abstract E Remove (int);  public abstract int indexOf (java.lang.Object);  public abstract int lastIndexOf (java.lang.Object);  Public abstract java.util.listiterator<e> listiterator ();  Public abstract java.util.listiterator<e> listiterator (int);  Public abstract java.util.list<e> sublist (int, int); Public java.util.spliterator<e> spliterator ();}
The list interface provides these methods, most of which are abstract, but some are not, and this is part of the new default method of JDK 1.8. For example, the sort method.

The list interface provides a random access method, such as the Get (int) method, but list and whether a particular implementation of these methods is efficient.

To avoid running expensive random access operations, Java SE 1.4 introduces a markup interface, randomaccess.

This interface is not available in any way, but can be used to detect whether a particular collection supports efficient random access:

if (c instanceof randomaccess) {Use the    random access algorighm}else{use    sequential access algorithm}
This interface is implemented by ArrayList.

The routine method in the list interface is implemented in the abstract class abstractlist, so that it does not need to be implemented in a detailed class, such as the IsEmpty method and the Contains method.

These routine methods are relatively simple. Meaning is also obvious. For classes of random access elements (for example, ArrayList), this abstract class is inherited precedence.

In the Abstractlist abstract class. There is an important domain. Called Modcount:

protected transient int modcount = 0;

This domain can be used to track the number of structural changes to a list, what are structural changes? is to change the length of the list, for example, add, delete, etc.

It is not a structural change to change the value of only one node.

This field is useful in later iterators.

Iterators are able to use this domain to detect concurrency changes, a problem that is described in the LinkedList class.

Abstract class Abstractsequentiallist implements some methods in the list interface, giving precedence to this abstract class for the class of sequential access elements (for example, LinkedList).

2 Linked list: LinkedList

A linked list is a well-known data structure.

The linked list overcomes the problem of inefficient insertion and deletion of arrays, and the insertion and deletion of linked lists is efficient.

The linked list stores each object in a separate node.

LinkedList linked list in Java, each node in addition to a post-order node reference, another pre-sequence node reference, that is. LinkedList is a doubly linked list.

The LinkedList class has three domains, each of which are size, head node, and tail nodes:

transient int size;transient node<e> first;transient node<e> last;

There are also two constructors, a non-reference constructor, and a constructor with a reference:

Public java.util.LinkedList ();p ublic java.util.LinkedList (java.util.collection<? extends e>);

None of the constructors constructs an empty linked list, and the constructor constructs a linked list based on a set that is passed in.

2.1 Node<e> Inner Class

In the LinkedList class, a node<e> inner class is defined to represent a node.

The definition of this class is as follows:

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;    }}
This is a static inner class, and there is no external reference. This class has three fields: values. A reference to a preamble node, a reference to a post-order node, and a constructor method. The definition is very easy.

Suppose you want to create a node that can:

Node<e> node=new node<> (pre,item,next);

The pre and next are respectively references to the pre-order node and the sequential node.

2.2 Basic methods of linked list operations

Since it is a linked list. The addition and deletion of linked list nodes is indispensable.

In the LinkedList class, there are six main methods for linking list operations. These methods alter the structure of the linked list, and therefore change the Modcount domain in the Abstractlist class, for example, the following six methods:

private void Linkfirst (e);//The node that joins the given value in the header of the list as the head node void Linklast (E);//Add a node with a given value at the end of the list as the tail node void Linkbefore (E, java.util.linkedlist$node<e>);//Insert a node in front of the given node private E Unlinkfirst (java.util.linkedlist$node<e>);// Delete the head node. and return the value of the head node private e unlinklast (java.util.linkedlist$node<e>);//delete the tail node and return the value of the tail nodes e unlink (java.util.linkedlist$ node<e>);//delete the given node
These methods are private (or private within the package). So it can be called a tool method, and all the structural changes in the LinkedList class are implemented based on these six methods.

These six methods are the basic operations of a list. The code is relatively simple. Just give the implementation can look at the source code implementation of the wording, for their own programming is also helpful:

    /** * Links e as first element.        */private void Linkfirst (E e) {final node<e> f = first;        Final node<e> NewNode = new node<> (null, E, F);        first = NewNode;        if (f = = null) last = NewNode;        else F.prev = NewNode;        size++;    modcount++;     }/** * Links e as last element.        */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++;     }/** * Inserts element e before Non-null Node succ.        */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++;     }/** * Unlinks non-null first node 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;     }/** * Unlinks non-null last node L.        */Private E Unlinklast (node<e> 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; }/** * Unlinks nOn-null node X.        */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; }
2.3 List iterator: Listiterator interface

A linked list is an ordered set. The location of each object is important. The Linkedlist.add method simply adds the node to the tail, but there is a significant part of the operation of the list that needs to be added to the middle of the list.

Because the iterator is in the position of the number of seconds in the collection. So the method of joining the dependent location is the responsibility of the iterator.

It only makes sense to use iterators to add elements to a naturally ordered collection.

For example, for unordered set set, there is no Add method in the iterator interface. Instead, the Listiterator interface is provided in the collection class library, which has the Add method:

Interface listiterator<e> extends iterator<e>{    void Add (E element);    ...}
Unlike the Add method in the collection interface, this method does not return a Boolean-type value. Because it assumes that the join operation always changes the linked list.

Other than that. In addition to the Hasnext and next methods, the Listiterator interface provides the following two methods:

E Previous (); Boolean hasprevious ();
These two methods are used to traverse the linked list in reverse. Previous, like next, returns objects that are crossed.

The Listiterator method of the LinkedList class returns an Iterator object:

Listiterator<string> Iter=list.listiterator ();
We know when we introduce the interface. An interface object cannot be instantiated. However, you can declare an interface object and then reference an instance of the class that implements the interface. Then the Listiterator method returns must be an instance of a class, and this class is bound to implement this interface, the problem is. What is this class?

This class is in fact an inner class of LinkedList, the LISTITR:

Compiled from "Linkedlist.java" class Java.util.linkedlist$listitr implements java.util.listiterator<e> {  Private java.util.linkedlist$node<e> lastreturned;  Private java.util.linkedlist$node<e> Next;  private int nextindex;  private int expectedmodcount;  Final java.util.LinkedList this$0;  Java.util.linkedlist$listitr (Java.util.LinkedList, int.);  public boolean hasnext ();  Public E next ();  public boolean hasprevious ();  Public E Previous ();  public int nextindex ();  public int previousindex ();  public void Remove ();  public void set (E);  public void Add (E);  public void foreachremaining (JAVA.UTIL.FUNCTION.CONSUMER<? super e>);  final void Checkforcomodification ();}
The above is also the result of using JAVAP to decompile. Can see. This inner class implements the Listiterator interface and implements the method of this interface.

This is the key to understanding iterators. We know that iterators can be seen as a place. This position is in the middle of two nodes, that is, for a linked list of size n, the position of the iterator is n+1:

| A | B | ...| Z |

In this example. The list represents 26 letters, and the position of the iterator is 27.

This is also the visualization of iterators as cursors. The next method is to move the cursor to the next position and return to the element you just crossed after meals, as well as previous. Just move left one position. It then returns the element that just crossed. The following are the code for these two methods:

Public E Next () {    checkforcomodification ();    if (!hasnext ())        throw new Nosuchelementexception ();    lastreturned = Next;    Next = Next.next;    nextindex++;    return Lastreturned.item;} Public E Previous () {    checkforcomodification ();    if (!hasprevious ())        throw new Nosuchelementexception ();    lastreturned = Next = (next = null)? Last:next.prev;    nextindex--;    return Lastreturned.item;}
These two methods first call the Checkforcomodifcation method to examine the concurrency change problem. As I said earlier, Abstractlist's Modcount records the number of changes in the list, and each iterator maintains a separate counter through the following fields:

private int expectedmodcount = Modcount;
This domain is initialized to the number of modcount changes to the class. The checkforcomodification checks whether the counters maintained by the iterator are equal to the modcount of the class, assuming unequal. Will throw a concurrentmodificationexception.

After the concurrency change check passes. The Hasnext or Hasprevious method is called to check if the element is to be visited. The Listitr class has a nextindex domain:

private int nextindex;
This domain maintains the current position of the iterator. Of course, for LinkedList, because the iterator points to the middle of two elements, it can produce two indexes at the same time: The Nextindex method returns the integer index of the element returned the next time the next method is called. Previousindex returns the index of the element returned the next time the previous method is called, which is 1 smaller than nextindex.

The Hasnext and Hasprevious methods are to check if Nextindex and Previousindex are in the right range to see if the element is actually being visited.

The Listitr class also has two domains:

Private node<e> lastreturned;private node<e> next;
The lastreturned is used to save the last node returned, and next is the next element in the position of the iterator. It can also be seen as the next element of the cursor (the next element is always the right side of the cursor). After calling the next method, the cursor moves right one bit. Go over the node that is saved in the next field, and then update the values of the two fields, that is, the next change to Lastreturned,next is the next element, and then the nextindex increases by 1.

Previous is equivalent to moving the cursor left one bit relative to the next operation, and when updating lastreturned and next, consider whether next is null. Assume that next is null, indicating that the previous is not running. The iterator is in the last position, so after running previous. Next should be the tail node last of the list. Assuming that next is not NULL, then next is updated to the preamble node of next. And lastreturned is the element that the cursor just crossed. Now the next node, lastreturned and next nodes point to the same element.

The Listitr class has three ways to change the list: Add, remove, and set. The Add and remove changes the position of the iterator. Because these two methods alter the structure of the linked list, the set method does not alter the position of the iterator. Because it does not alter the structure of the linked list.

The code for these three methods is as follows:

public void Remove () {    checkforcomodification ();    if (lastreturned = = null)        throw new IllegalStateException ();    node<e> lastnext = Lastreturned.next;    Unlink (lastreturned);    if (next = = lastreturned)        next = Lastnext;    else        nextindex--;    lastreturned = null;    expectedmodcount++;} public void Set (E e) {    if (lastreturned = = null)        throw new IllegalStateException ();    Checkforcomodification ();    Lastreturned.item = e;} public void Add (e e) {    checkforcomodification ();    lastreturned = null;    if (next = null)        linklast (e);    else        Linkbefore (e, next);    nextindex++;    expectedmodcount++;}
It is worth noting that the Remove method.

The lastreturned is set to NULL after each call to the Remove method. Other words. Assuming that the Remove method is called consecutively, the second call throws a IllegalStateException exception.

So. The remove operation must follow the next or previous operation.

Now we have introduced the basic method of the Listiterator interface, which can traverse the elements in the linked list from the front and back two directions, and can join and delete elements.

Remember one point: adding and removing nodes from any location in the list is provided by the Listiterator iterator, and the Add method of the class itself can only be added at the end.

2.4 Random Interview

In the Java class Library, there are many theories that have some controversial methods. The linked list does not support high-speed random access. Suppose you want to see the nth element in a linked list, you have to start from scratch. Crossing n-1 elements, there is no shortcut to go. For this reason. When a program needs to use an integer index to access an element. Generally do not use linked lists.

Nonetheless, the LinkedList class provides a Get method to access a particular element:

Linkedlist<string> list= ...; String s=list.get (n);
Of course, the efficiency of this method is not very high.

You should never use such a misleading random access method to traverse a linked list. The following code is extremely inefficient:

For (int. i=0;i<list.size (); i++) {    dosomething with list.get (i);}

Every time you look up an element, you start searching again. The LinkedList object does not do any processing of cache location information at all.

In fact. In the LinkedList class, the Get method infers where the current position is closer to the end of the head and tail, and then infers whether to traverse from left to right or from right to left.

2.5 examples

The following code demonstrates the basic operation of the LinkedList class.

It simply creates two linked lists, merges them together, and then deletes one element from each interval in the second linked list. The last Test RemoveAll method:

import java.util.*;p Ublic class Linkedlisttest {public static void main (string[] args) {list<string> a=new Link        Edlist<> ();        A.add ("A");        A.add ("C");        A.add ("E");        List<string> b=new linkedlist<> ();        B.add ("B");        B.add ("D");        B.add ("F");        B.add ("G");        Listiterator<string> Aiter=a.listiterator ();        Iterator<string> Biter=b.iterator ();            while (Biter.hasnext ()) {if (Aiter.hasnext ()) Aiter.next ();        Aiter.add (Biter.next ());        } System.out.println (a);        Biter=b.iterator ();            while (Biter.hasnext ()) {biter.next ();                if (Biter.hasnext ()) {biter.next ();            Biter.remove ();        }} System.out.println (b);        A.removeall (b);    System.out.println (a); }}
The results are as follows:


3 List of arrays: ArrayList

The list interface and the LinkedList class that implements this interface are described earlier. The list interface is used to describe an ordered set, and the position of each element in the collection is important.

There are two protocols to access elements: one is to use iterators. There is also a random access to each element using the get and set methods.

The latter does not apply to linked lists, but arrays are very useful. The Collection Class library provides a very familiar ArrayList class, which also implements the list interface. The ArrayList class encapsulates an array of dynamically redistributed objects.

Another dynamic array in the Java Collection Class Library: the Vector class. Just the whole method of this class is synchronous and can be visited by a vector object by two threads safely.

However, suppose a thread visits a vector. The code consumes a lot of time on synchronization.

And the ArrayList method is not synchronous, so. Assume that you do not need to use ArrayList when synchronizing.

The implementation of the class and the use of the method are introduced concretely in the ArrayList concrete explanation.

Java collection (b): List of lists

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.