Java Traversal Set Method analysis (Implementation principle, algorithm performance, applicable occasions) _javascript skills

Source: Internet
Author: User

Overview

In the Java language, a set of data collection framework is provided, which defines some abstract data types such as list, set, each concrete implementation of each abstract data type, and uses different implementations in the bottom layer, such as ArrayList and LinkedList.

In addition, Java provides several different ways to traverse the data collection. Developers must be clear about the characteristics of each traversal, where it fits, and how it behaves at different levels of implementation. Here is a detailed analysis of this piece of content.

How is the data element stored in memory?

Data elements in memory, there are mainly 2 ways to store:

1, sequential storage, Random access (Direct access):

In this way, adjacent data elements are stored in adjacent memory addresses, and the entire memory address is contiguous. The memory address can be computed directly from the location of the element and read directly. The average time complexity for reading a particular location element is O (1). Normally, only a collection based on an array implementation has this feature. In Java, it is represented by ArrayList.

2, chained storage, sequential Access:

In this way, each data element, in memory, does not require an adjacent position, and each data element contains the memory address of its next element. The memory address cannot be computed directly from the location of the element, and only the elements can be read sequentially. The average time complexity for reading a particular location element is O (n). Mainly in the linked list as a representative.

In Java, it is represented by LinkedList.

What are the traversal methods provided in Java?

1, the traditional for loop traversal, based on the counter:

The traversal maintains a counter on its own outside the collection and then reads the elements of each position sequentially, stopping after reading the last element. The main thing is to read elements by their location. This is also the most original set traversal method.

Written as:

for (int i = 0; i < list.size (); i++) {
list.get (i);

2, iterator traversal, iterator:

Iterator was originally an OO design pattern, the main purpose is to mask the characteristics of different data sets, unified traversal of the interface of the collection. Java, as an OO language, naturally supports the iterator model in collections.

Written as:

Iterator iterator = List.iterator ();
while (Iterator.hasnext ()) {
iterator.next ();
}

3, foreach Loop traversal:

Masks iterator and counters that are explicitly declared.

Advantages: Simple code, not easy to make mistakes.

Disadvantage: Can only do a simple traversal, not in the traversal process (delete, replace) data collection.

Written as:

for (ElementType element:list) {
}

What is the implementation principle of each traversal method?

1, the traditional for loop traversal, based on the counter:

The traversal maintains a counter on its own outside the collection and then reads the elements of each position sequentially, stopping after reading the last element. The main thing is to read elements by their location.

2, iterator traversal, iterator:

Each data collection of the specific implementation, generally need to provide the corresponding iterator. Compared to the traditional for-loop, iterator the explicit traversal counter. Therefore, iterator based on sequential storage collections can access data directly by location. And based on chained storage set of iterator, the normal implementation, is the need to save the current traversal of the location. Then move the pointer forward or backward according to the current position.

3, foreach Loop traversal:

Based on the deserialized bytecode, it is found that foreach is implemented in a iterator way internally, except that the Java compiler helped us generate the code.

What is the performance of each traversal method for different storage modes?

1, the traditional for loop traversal, based on the counter:

Because it is based on the location of the element, read by position. So we can see that for sequential storage, because the average time complexity of reading a particular location element is O (1), the average time complexity of traversing the entire set is O (n). For chained storage, because the average time complexity of reading a particular location element is O (n), the average time complexity of traversing the entire set is O (N2) (square of N).

ArrayList code read by location: Read directly by element position.

Transient object[] elementdata;
Public E get (int index) {
Rangecheck (index);
Return Elementdata (index);
}
e elementdata (int index) {return
(e) elementdata[index];

LinkedList code read by location: Each time you need to read backwards from the No. 0 element. In fact, it also made a small optimization inside.

transient int size = 0;
Transient node<e>;
Transient node<e> last;
Public E get (int index) {
checkelementindex (index);
Return node (index). Item;
node<e> node (int index) {
if (Index < (size >> 1)) {//query location in the first half of the list, search from the head of the list
node<e> x = Fir St;
for (int i = 0; i < index; i++)
x = X.next;
return x;
} else {//query location in the second half of the list, starting at the end of the list
node<e> x = last;
for (int i = size-1 i > index; i--)
x = X.prev;
return x;
}
}

2, iterator traversal, iterator:

So there is not much meaning to the collection of randomaccess types, but because of some extra operations, additional running time is added. But for a collection of sequential access, it's very important because the iterator internally maintains the current traversal, so each traversal, reading the next location does not need to start looking from the first element of the collection, so just move the pointer back one, so that The time complexity of traversing the whole set is reduced to O (n);

(Here only use LinkedList as an example) LinkedList iterator, internal implementation, is to maintain the current traversal of the location, and then the operation of the pointer to move on it:

Code:

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;
}

3, foreach Loop traversal:

Analysis of Java bytecode know, foreach internal implementation principle, but also through the iterator implementation, but this iterator is the Java compiler to help us build, so we do not need to manually write. But because you have to do a type conversion check each time, it takes a little longer than iterator. The complexity of time is the same as iterator.

Use iterator byte code:

Code:
New #//class java/util/arraylist
dup
invokespecial #//Method Java/util/arraylist. <init> ":() V
astore_
aload_
invokeinterface #,//Interfacemethod Java/util/list.iterator: () Ljava /util/iterator;
Astore_
goto 
aload_
invokeinterface #,//Interfacemethod Java/util/iterator.next: () ljava/lang/object ;
Pop
Aload_
invokeinterface #,//Interfacemethod Java/util/iterator.hasnext: () Z
Ifne 

Use a foreach byte code:

Code:
New #//class java/util/arraylist
dup
invokespecial #//Method Java/util/arraylist. <init> ":() V
astore_
aload_
invokeinterface #,//Interfacemethod Java/util/list.iterator: () Ljava/util/iterator;
Astore_
goto 
aload_
invokeinterface #,//Interfacemethod Java/util/iterator.next: () ljava/lang/ Object;
Checkcast #//class Loop/model
astore_
aload_
invokeinterface #,//Interfacemethod java/util/ Iterator.hasnext: () Z
Ifne 

What is the application of each traversal method?

1, the traditional for loop traversal, based on the counter:

Sequential storage: Read performance is relatively high. Applies to traversal sequential storage collections.

Chained storage: The time complexity is too high to be used to traverse a chain-store collection.

2, iterator traversal, iterator:

Sequential storage: If not too concerned about the time, recommend this approach, after all, the code is more concise, but also to prevent the problem of off-by-one.

Chained storage: The significance is significant, the average time complexity down to O (n), or very attractive, so recommend this traversal method.

3, foreach Loop traversal:

foreach just makes the code more concise, but he has some drawbacks, that is, the traversal process can not manipulate the data collection (delete, etc.), so some occasions do not use. And it is based on iterator implementation, but because of the problem of type conversion, so it will be slower than the direct use of iterator, but fortunately, time complexity is the same. So how to choose, refer to the above two ways, make a compromise choice.

What is the best practice for Java?

In the Java Data Collection framework, a randomaccess interface is provided that has no method, just a tag. is usually used by the implementation of the list interface to mark whether the implementation of the list supports random Access.

A data collection implements this interface, meaning that it supports random Access, and the average time complexity of reading elements by location is O (1). Like ArrayList.

Without the implementation of this interface, random Access is not supported. Like LinkedList.

So it seems that JDK developers are also aware of this problem, the recommended practice is, if you want to traverse a list, then first determine whether to support random Access, that is, List instanceof randomaccess.

Like what:

if (list instanceof randomaccess) {
//Use the traditional for loop traversal.
else {
//use iterator or foreach.
}

The above is a small series to introduce the Java Traversal Set method analysis (Implementation principle, algorithm performance, applicable occasions), I hope to help you!

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.