LinkedList of the Java collection

Source: Internet
Author: User
Tags addall int size

1. Initial knowledge of LinkedList

In the previous article explained the ArrayList, this article explains the LinkedList realization.

LinkedList is based on a linked list , so let's start by explaining what a list is. The list was originally a C/s + + concept, a linear storage structure, meaning that the data to be stored in a storage unit inside, in addition to storing the data to be stored, it also stores the address of its next storage unit (the address of the next storage unit is necessary, Some storage structures also hold the address of their previous storage unit, and each time the data is looked up, the address of the next storage unit in a storage unit is searched for the storage unit behind it.

So it may be a little abstract, first of all, LinkedList is a doubly linked list, two-way list I think there are two points meaning:

1. Any storage unit in the linked list can be obtained by means of forward or backward addressing to its previous storage unit and subsequent storage unit

2, the last node of the tail node of the linked list is the head node of the linked list, and the previous node of the list's head node is the tail of the linked list.

2.LinkedList Data Structure principle

LinkedList the underlying data structure is based on a two-way cyclic linked list , and the head node does not store the information, as follows:

Since it is a doubly linked list, there must be a data structure--we can call it nodes, the node instance holds the business data, the location information of the previous node, and the next node location information, as shown in:

3. Private properties

Two private attributes are defined in LinkedList:

Private transient entry<e> Header = new entry<e> (null, NULL, NULL);p rivate transient int size = 0;

The header is the head node of the doubly linked list, which is an instance of the class entry corresponding to the doubly linked list node. Entry contains member variables: Previous, next,element. Where previous is the node's previous node, next is the node's next node, and element is the value that the node contains.
Size is the number of node instances in a doubly linked list.

First, learn the code for the node class entry 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;   }}

See the "E element" in LinkedList's entry, which is the data it really stores. "Entry<e> Next" and "Entry<e> previous" represent the reference address of the previous storage unit of this storage unit and the reference address of the latter storage unit. The diagram shows that:

4. Constructors

LinkedList provides two construction methods, as follows:

Public LinkedList () {    Header.next = Header.previous = header;} Public LinkedList (collection<. extends e> c) {this    ();   AddAll (c);}

The first constructor does not accept parameters, and the header instance's previous and next all point to the header instance (note that this is a two-way loop linked list, if it is not a circular linked list, the case of the empty list should be the header node of the previous node and the latter node are null), So the entire list is actually only the header of a node, used to represent an empty linked list.

After the constructor is executed, the header instance itself forms a closed loop, as shown in:

The second constructor receives a collection parameter, C, calls the first constructed method to construct an empty linked list, and then adds all the elements in C to the linked list by AddAll.

5. Four points of concern on the LinkedList answer

Focus Point Conclusion
LinkedList whether NULL is allowed Allow
LinkedList whether duplicate data is allowed Allow
Whether the LinkedList is orderly Ordered
LinkedList is thread safe Non-thread safe

Second, add elements

First look at the LinkedList add an element is how to do, if I have a piece of code:

1 public static void main (string[] args) 2 {3     list<string> List = new Linkedlist<string> (); 4     List.add ("111"); 5     List.add ("222"); 6}

row by line analysis of the main function of the three lines of code is how to execute, first of all, the 3rd line, look at the source of LinkedList:

1 public class Linkedlist<e> 2     extends abstractsequentiallist<e> 3     implements List<e>, Deque <e>, cloneable, java.io.Serializable 4 {5     private transient entry<e> header = new entry<e> (null, NU ll, NULL);  6     private transient int size = 0; 7  8     /** 9      * Constructs an empty list.10      */11 public     LinkedList () {         Header.next = header.previous = header;13     }14     ... 15}

See, new A entry out named Header,entry inside the previous, element, Next are null, when the constructor is executed, the values of previous and next are set to the reference address of the header, Or in the form of a drawing. The 32-bit JDK has a word length of 4 bytes, and the current 64-bit JDK generally uses 4 word lengths, so it is in 4 words. The word length of the header reference address is 4 bytes, assuming that it is 0x00000000, then after executing "list<string> List = new linkedlist<string> ()" You can say:

Then look at line 4th add a string "111" to do what:

1 public boolean Add (E e) {2     addbefore (e, header); 3     return true;4}
1 Private entry<e> Addbefore (e E, entry<e> Entry) {2     entry<e> newEntry = new Entry<e> (E, Entry , entry.previous); 3     newEntry.previous.next = newentry;4     newEntry.next.previous = newentry;5     size++;6     modcount++;7     return newentry;8}

The Addbefore (E e,entry<e> Entry) method is a private method, so it cannot be called in an external program (this is, of course, the general case, which you can do by reflecting the above or can be called).

Addbefore (e e,entry<e> Entry) first creates the node newentry of E through the Entry construction method (which includes setting its next node to Entry, The previous node is set to Entry.previous, which is equivalent to modifying the Newentry "pointer"), after modifying the next reference of the previous node newentry the insertion position and the previous reference of the latter node, so that the referential relationship between the list nodes remains correct. After modifying and resizing the size and record Modcount, then return the newly inserted node.

The 2nd line new A entry out, may not be very good to understand, according to entry's constructor, I put this sentence "translated" a bit, may be good to understand:

1, newentry.element = e;

2, Newentry.next = header;

3, newentry.previous = header.previous;

The reference address for the header is already seen in 0x00000000,header.previous, and is 0x00000000, so assume that the address of the new entry is 0x00000001, and continues drawing:

A total of five steps, each step of the operation steps are expressed in numbers:

1, the new entry element is assigned a value of 111;

2, the new entry next is the reference address of the header, the reference address of the header is 0x00000000, so the new entry next is 0x00000000;

3, the new entry previous is the header of the Previous,header previous is 0x00000000, so the new entry next namely 0x00000000;

4, "NewEntry.previous.next = NewEntry", the first is the previous of NewEntry, because NewEntry previous for 0x00000000, So Newentry.previous said that Header,header's next is newentry, that is, the header of next is 0x00000001;

5, "newEntry.next.previous = NewEntry", and 4, the header of the previous set to 0x00000001;

Why do you do this? Remember the two-way list of two characteristics, one is that any node can be forward and backward addressing, the second is the entire chain of the head of the previous represents the tail of the list of entry, the end of the list of the link is the head of the list entry. Now the chain of the head is 0x00000000 this entry, the tail of the chain is 0x00000001, you can look at the picture to see, think about whether it meets these two conditions.

Finally look at add a string "222" What to do, assuming that the address of the new entry is 0x00000002, drawing means:

or the implementation of the 5 steps, each step of the figure is marked out, as long as you want to know previous, next each of which node is not a problem.

At this point, adding a string "111" and a string "222" to a LinkedList is complete. It should be easier to understand the doubly linked list from this diagram:

1, the middle of the value of the entry,previous is 0x00000000, that is, the value of Header;next is 0x00000002, that is, tail, which is any one entry can either forward to find entry, can also look backwards entry.

2, the previous value of the head entry is 0x00000002, that is, tail, this is the doubly linked list in the head entry previous point to the tail entry.

3, the next value of the tail entry is 0x00000000, that is, the header, which is the two-way list in the tail entry of the next point is the head entry.

Third, view elements

Take a look at how the LinkedList code is written:

Public E get (int index) {    return Entry (index). element;}
1//Get node     2 private entry<e> Entry (int index) {     3     if (Index < 0 | | | index >= size) for the specified position in the doubly linked list     4< C4/>throw new Indexoutofboundsexception ("Index:" +index+     5                                             ", Size:" +size);     6     entry<e> E = header;     7     //Gets the node at index.     8     //If index < bidirectional list length is 1/2, then look backwards from front to back;     9     //Otherwise, look forward from behind.     if (Index < (size >> 1)) {One    for         (int i = 0; I <= index; i++)             e = E.next ;         (int i = size; i > Index; i--)             e = e.previous;    + (+    ) +     return e;    18}

The Get (int) method first determines whether the location information is valid (greater than or equal to 0, less than the size of the current LinkedList instance), and then traverses to the specific location to obtain the node's business data (element) and return.
Note: To improve efficiency, you need to determine whether you want to iterate from the beginning or from the end, depending on the location obtained.

This code shows the benefits of a doubly linked list. The doubly linked list adds a little bit of space consumption (each entry also maintains its pre-entry references), while adding a certain degree of programming complexity, which greatly improves efficiency.

Since LinkedList is a doubly linked list, LinkedList can either look forward or look backwards, and line 10th ~ 16th is: when index is less than half the size of the array (size >> 1 means size/ 2, using the shift operation to improve the efficiency of the code), looking backwards from the front; otherwise, look forward from the back .

In this way, in my data structure there are 10,000 elements, it happens to find the 10,000th element, it does not need to traverse 10,000 times, the backward traversal can be, one can find the element I want.

Attention to detail: the difference between bitwise arithmetic and direct division. Compare index to half of the length size first, if INDEX<SIZE/2, only from position 0 to the position index, and if INDEX>SIZE/2, only from the position size forward to the position index. This reduces the unnecessary traversal of a part.

Iv. deleting elements

After reading the add element, let's look at how to delete an element. Like ArrayList, LinkedList supports deleting by element and pressing subscript, which deletes the first element that matches from the beginning. Use the subscript to delete for example, let's say there's a code like this:

1 public static void main (string[] args) 2 {3     list<string> List = new Linkedlist<string> (); 4     List.add ("111"); 5     List.add ("222"); 6     list.remove (0); 7}

That is, I want to delete the "111" element. Take a look at how line 6th is executed:

1 1 public E Remove (int index) {2 2     return Remove (Entry (index)); 3 3}
1 Private e Remove (entry<e> e) {2     if (e = = header) 3         throw new Nosuchelementexception (); 4     //Keep the node that will be removed Content of e 5     e result = e.element; 6     //assigns the next reference of the previous node to the next node of E, 7     e.previous.next = E.next; 8     //Will previous of the next node of E The previous node assigned to E is 9     e.next.previous = e.previous;10     //The execution of the above two statements has resulted in the inability to access the E node in the linked list, and the following removes the reference to the front and back nodes of the e node     e.next = E.previous = null;12     //The content of the removed node is set to Null13     e.element = null;14     //Modify size to     size--;16     MODCOUNT++;17     //Returns the contents of the removed node e return     result;19}

Of course, the first thing to find is where the element is, and this is the same as get. Then, it is easier to illustrate it in a drawing way:

Relatively simple, as long as the reference address to find the good, each step of the operation is also detailed in the diagram.

As a result of deleting a node, adjust the front and back pointer information of the corresponding node as follows:

E.previous.next = e.next;//The back pointer of the previous node of the pre-deleted node points to the next node of the pre-deleted node.

E.next.previous = e.previous;//The front pointer of the next node of the pre-deleted node points to the previous node of the pre-deleted node.

To empty a pre-deleted node:

E.next = e.previous = null;

E.element = null;

The GC completes the resource collection and the delete operation ends.

In contrast to ArrayList, LinkedList's delete action does not need to "move" a lot of data, making it more efficient.

Here I mention that the 3rd, 4th, 5th steps will be deleted entry's previous, element, next are set to NULL, the role of these three steps is to let the virtual machine can reclaim this entry.

V. Comparison of LinkedList and ArrayList

The cliché of the problem, here I try to understand their own understanding of this problem, by the way here to the linkedlist of the pros and cons also told.

1, sequential insertion speed ArrayList will be faster, because ArrayList is based on the implementation of the array, the array is in advance new good, as long as the specified location to plug a data is good; LinkedList is different, Each time the order is inserted LinkedList will be a new object, if the object is larger, then new time is bound to grow a bit, plus some reference assignment operation, so the sequential insertion of linkedlist must be slower than ArrayList

2, based on a point, because the linkedlist inside not only maintain the elements to be inserted, but also maintain the entry entry and subsequent entry, if a linkedlist very much, Then LinkedList will consume some more memory than ArrayList.

3, some say that linkedlist do insert and delete faster, this statement is actually inaccurate:

(1) LinkedList do insert, delete time, slow in addressing, fast in only need to change the entry before and after the reference address

(2) ArrayList do insert, delete, slow in the array elements of the bulk copy, fast in addressing

Therefore, if the element to be inserted and deleted is in the first half of the data structure, especially in the front position, the efficiency of linkedlist will be much faster than ArrayList, because ArrayList will bulk copy a large number of elements; For LinkedList, because it is a doubly linked list, inserting a data after the 2nd element and inserting an element after the 2nd element is basically no different in efficiency, but ArrayList because there are fewer elements to bulk copy, The operation speed must catch up with even surpass LinkedList.

From this analysis, if you are very sure that the elements you insert and delete are in the first half, then use LinkedList, and if you are very sure that the elements you delete and delete are in the post-comparison position, consider using ArrayList. If you are not sure where you want to insert and delete? It is recommended that you use the LinkedList bar, because one linkedlist the overall insertion, deletion of the execution efficiency is relatively stable, there is no ArrayList the faster the situation, and then insert the element, it is not good ArrayList will be the expansion, remember, ArrayList the underlying array expansion is an operation that consumes both time and space.

LinkedList of the Java collection

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.