LinkedList is similar to the two-way linked list in the C language, but there is no pointer in Java to implement it. After reading LinkedList, you will have more in-depth understanding of the reference types in Java. The declaration of LindedList is as follows:
public class LinkedList extends AbstractSequentialList implements List, Cloneable, java.io.Serializable about AbstractSequentialList: http: //blog.9cbs.net/treeroot/archive/2004/09/18/108696.aspx about List: http: // blog. 9cbs.net/treeroot/archive/2004/09/14/104638.aspx about cloneable: http://blog.9cbs.net/treeroot/archive/2004/09/07/96936.aspx
The implementation of this linked list is analyzed below, and some methods are only analyzed.
Private transient entry header = new entry (null, null, null); private transport int size = 0; public linkedlist () {header.next = header.previous = header;} Header is equivalent to the head pointer in C, and this head The pointer is not an element of a linked list, and the entry will be described below.
Public LinkedList (Collection C) {this (); addall (c);}
Public Object getFirst () {if (size == 0) throw new nosuchelementException (); return header.next.Element;} The next element of the head pointer is the first element
Public Object getLast () {if (size == 0) throw new nosuchelementException (); return header.previous.Element;} The first one of the head pointer is of course the last one.
Public Object Removefirst () {Object first = header.next.Element; remove (header.next); return first;}
Public Object Removelast () {Object Last = Header.Previous.Element; Remove (Header.Previous); Return Last;}
Public void addfirst (Object O) {addbefore (o, header.next);}
Public void addlast (Object O) {addbefore (o, header);} This method is inserted into new elements, functions, and add methods at the end of the chain table, this method is completely for symmetry (because there is AddFirst)
Public Boolean Contains (Object O) {Return IndexOf (O)! = -1;}
Public int size () {return size;}
Public Boolean Add (Object O) {Addbefore (O, Header); Return True;}
Public Boolean Remove (Object O) {if (o == null) {for (entry E = header.next; e! = header; e = E.next) {if (e.element == null) {transove (e ); Return true;}}}} else {for (ENTRY E = header.next; e! = Header; e = E.NEXT) {IF (O.Equals (EE.Element)) {Remove (E); Return True }}} Returnaf false; Public Boolean Addall (Collection C) {Return Add (Size, C);}
Public Boolean Addall (int index, collect c) {int NumNew = C.Size (); if (Numnew == 0) Return False; Modcount ;
Entry successor = (index == size? Header: entry (index)); entry predecessor = successe; item it = c.ITerator (); for (int i = 0; i
Entry E = New Entry (it.next (), success, predeessor;
Predecessor.next = E;
Predecessor = E;
}
Successor.previous = predecessor;
Size = Numnew; Return True;} Here is the familiar face, inserting an element in the linked list in the data structure is not the case? Successor represented a pointer, that is, inserted data in front, Predecessor represents the previous pointer, which is to insert the pointer before the data is inserted. If you understand the data structure, it should be easier to understand. Here I can change the code, but it is not an optimization: for (int i = 0; i
Entry E = New Entry (it.next (), null, predecessor;
Predecessor.next = E;
Predecessor = E;
}
Predecessor.next = Successor;
Successor.previous = predecessor;
This is the same, if the entry has such a constructor entry (Object element, entry previous), then optimized with the modified code (not much value). If you can understand why you can modify this, you can fully understand that if you are not familiar with this data structure, you can draw a list, then press the code to modify your linked list, this method is very effective.
Public void clear () {modcount ; header.next = header.previous = header; size = 0;} public object get (int index) {return entry (index) .Element;}
Public Object Set (int index, object element) {entry e = entry (index); object ilval = E.Element; E.Element = Element; returna}
Public void add (int index, object element {addbefore (element, (index == size? header: entry (index)));}
Public Object Remove (int index) {entry E = entry (index); REMOVE (E); Return E.Element;
Private entry entry (int index) {IF (index <0 || index> = size) throw new indexoutofboundsexception ("INDEX:" index ", size:" size); entry E = header; if (index <(Size >> 1)) {for (int i = 0; i <= index; i ) E = E.NEXT;} else {for (int i = size; I> index; i -) E = E.PREVIOS; } Return E;} This method returns an entry, hereby Note that when index is 0, it is Head.Next, it is impossible to return to Head. Because INDEX> = 0
So the loop statement is at least once. Here the pointer movement is optimized because it is a two-way linked list, which can move in different directions, and Size >> 2 corresponds to size = size / 2
Public int indexof (object o) {int index = 0; if (o == null) {for (entry e = header.next; e! = header; e = e.next) {if (e.Element == null Return Index; Index ;}} else {for (entry E = header.next; e! = Header; e = E.NEXT) {i.equals (e.element)) Return Index; Index ;}} Return -1;} The only note here is the location of Index
Public int LastIndexof (Object O) {INDEX = size; if (o == null) {for (entry E = header.previous; e! = header; e = e.previous) {index -; if (e. ELEMENT == NULL) RETURN INDEX;}}} else {for (entry E = header.previous; e! = header; e = e.previous) {index--; if (O.Equals (E.Element) Return INDEX }}} Return -1;} Note Index - position public listiterator Listiterator (int index) {return new listitr (index);
The following is a private class internal private class ListItr implements ListIterator {private Entry lastReturned = header; private Entry next; node private // call next () method int nextIndex; private int expectedModCount = modCount;
Listitr (int index) {if (INDEX <0 || index> size) throw new indexoutofboundsexception ("INDEX:" INDEX ", SIZE:" size); if (Index <(Size >> 1)) {next = Header.next; for (nextIndex = 0; NextIndex
Next = next.next;
} else {
NEXT = header;
For (NextIndex = size; nextindex> index; NextIndex -)
Next = next.previous;
}
}
Public Boolean Hasnext () {Return NEXTINDEX! = size;}
public Object next () {checkForComodification (); if (nextIndex == size) throw new NoSuchElementException (); lastReturned = next; next = next.next; nextIndex ; return lastReturned.element;}
Public Boolean Hasprevious () {Return NEXTINDEX! = 0;
public Object previous () {if (nextIndex == 0) throw new NoSuchElementException (); lastReturned = next = next.previous; nextIndex--; checkForComodification (); return lastReturned.element;}
Public int nextindex () {return nextindex;} public int readyIndex () {return nextIndex-1;}
public void remove () {checkForComodification (); try {LinkedList.this.remove (lastReturned);} catch (NoSuchElementException e) {throw new IllegalStateException ();} if (next == lastReturned) // call is deleted here represented Previous () returned. Next = lastreturned.next; // next is deleted, so NEXT is backward, the index is constant. Else nextindex ---; // Delete is next.previous, so the index should be reduced by 1. LastReturned = header; // This is important: 1. Release the resource. 2. Remove is not allowed. EXPECTEDMODCOUNT ;
Public void set (Object O) {if (LastReturned == Header) throw new illegalstateException (); checkforcomodification (); LastRetund.Element = O;
Public Void Add (Object O) {CheckforComodification (); LastReturned = Header; Addbefore (O, Next); NextIndex ; ExpectedModcount ;}
Final Void CheckforComodification () {if (MODCOUNT! = EXPECTEDMODMODCOUNT) throw new concurrentmodificationException ();}}
The following is the definition of Entry: private static class entry {object element; entry prep
Entry (Object Element, Entry Next, Entry Previous) {this.Element = Element; this.next = next; this.previous = previous;}} is simple, is a two-way linked list, only one constructor, no other method. Isn't NEXT and PREVIOUS here? Isn't it just a pointer in a C! However, the C language does not handle the empty pointer, directly processes the operating system, Java does throw a system exception NullPointerexception, which does not give him the opportunity to destroy the system.
private Entry addBefore (Object o, Entry e) {Entry newEntry = new Entry (o, e, e.previous); newEntry.previous.next = newEntry; newEntry.next.previous = newEntry; size ; modCount ; return newEntry;} Private Void Remove (ENTRY E) {IF (E == Header) throw new nosuchelementException (); E.PREVIOSNEXT = E.NEXT; E.NEXT.PREVIOUS = E.PREVIOS; Size -; Modcount ;}
Public Object Clone () {LinkedList Clone = NULL; Try {Clone = (LinkedList) Super.clone ();} catch (clonenotsupportedException E) {throw new interroup ();}
// Put Clone Into "Virgin" State Clone.Header = New Entry (null, null, null); Clone.Header.next = Clone.Header.previous = Clone.Header; Clone.Size = 0; Clone.Modcount = 0 ;
// Initialize Clone with out; e-! = Header; e = E.NEXT) Clone.Add (E.Element); Return Clone;
Public object [] toArray () {object [] result = new object [size]; int i = 0; for (entry e = header.next; e! = header; e = e.next) Result [i ] = e .Element; Return Result;}}
Public object [] toarray (object a []) {if (a.length
"privatina"
Private synchronized void writeObject (java.io.objectOutputstream s) throws java.io.ioException {// Write out any hidden serialization magic s.defaultwriteObject ();
// WRITE OUT SIZE S.WRITEINT (SIZE);
// WRITE OUT All Elements in The Proper Order. For (ENTRY E = Header.Next; E! = Header; E = E.Next) S.WriteObject (EE.Element);
private synchronized void readObject (java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {// Read in any hidden serialization magic s.defaultReadObject ();
// read in size int size = sready = s.readint ();
// Initialize header header = new entry (null, null, null); header.next = header.previous = header;
// read in all elements in the project order. For (INT i = 0; i
Add (S.ReadObject ());
}
Here and ArrayList has a difference that Size is declared as transient because the Add method is called, so size will be automatically increased, and in ArrayList assigns a value (efficiency).
Here, ArrayList and LinkedList: 1.ArrayList are based on arrays, and LinkedList is implemented based on linked list. 2. For random access GET and SET, ArrayList feel better than LinkedList, because LinkedList wants to move the pointer. 3. For additional and delete operations, add and remove, LinedList, because ArrayList is to move data. 4. Find Operation INDEXOF, LastIndexOf, Contains, etc., both are almost. Here is theoretical analysis, in fact, it is not necessarily, such as ArrayList is inserted and deleted data, but there is still such a suggestion: Random access is more, you must use ArrayList instead of LinkedList, if you need frequent Insert and delete should consider using LinkedList to improve performance.