Java > Java Collections Framework > List, Set, and Map Interfaces > ArrayList vs LinkedList
ArrayList vs LinkedList: Basic Operations
This snippet demonstrates the fundamental differences in performance between ArrayList and LinkedList when performing common operations like adding, getting, and removing elements. The example highlights scenarios where one data structure is more efficient than the other.
Code Demonstration: ArrayList vs LinkedList
This code compares the performance of `ArrayList` and `LinkedList` for common operations. 1. Initialization: Two lists, `arrayList` (an `ArrayList`) and `linkedList` (a `LinkedList`), are created. 2. Adding at the end: Elements are added to the end of both lists, and the time taken is measured. `ArrayList` is usually faster for this, as it uses a dynamically resizing array. 3. Adding at the beginning: Elements are inserted at the beginning of both lists. `LinkedList` is generally much faster here because it only needs to update the head, while `ArrayList` needs to shift all existing elements. 4. Accessing elements: Elements are accessed by their index using `get()`. `ArrayList` provides faster access because it can directly access elements using their index (constant time). `LinkedList` needs to traverse the list from the head to find the element (linear time). 5. Removing elements from the beginning: This part tests removing elements from the front of the list. `LinkedList` is more efficient because it only updates head pointer, but `ArrayList` has to shift all the remaining elements.
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class ListComparison {
public static void main(String[] args) {
// Initialize lists
List<Integer> arrayList = new ArrayList<>();
List<Integer> linkedList = new LinkedList<>();
int numElements = 100000; // Adjust number of elements for testing
// --- Adding elements at the end ---
long startTime = System.nanoTime();
for (int i = 0; i < numElements; i++) {
arrayList.add(i);
}
long endTime = System.nanoTime();
System.out.println("ArrayList add (end): " + (endTime - startTime) / 1000000 + " ms");
startTime = System.nanoTime();
for (int i = 0; i < numElements; i++) {
linkedList.add(i);
}
endTime = System.nanoTime();
System.out.println("LinkedList add (end): " + (endTime - startTime) / 1000000 + " ms");
// --- Adding elements at the beginning ---
arrayList = new ArrayList<>();
linkedList = new LinkedList<>();
startTime = System.nanoTime();
for (int i = 0; i < numElements; i++) {
arrayList.add(0, i); // Add at the beginning
}
endTime = System.nanoTime();
System.out.println("ArrayList add (beginning): " + (endTime - startTime) / 1000000 + " ms");
startTime = System.nanoTime();
for (int i = 0; i < numElements; i++) {
linkedList.add(0, i); // Add at the beginning
}
endTime = System.nanoTime();
System.out.println("LinkedList add (beginning): " + (endTime - startTime) / 1000000 + " ms");
// --- Accessing elements (get) ---
startTime = System.nanoTime();
for (int i = 0; i < numElements; i++) {
arrayList.get(i);
}
endTime = System.nanoTime();
System.out.println("ArrayList get: " + (endTime - startTime) / 1000000 + " ms");
startTime = System.nanoTime();
for (int i = 0; i < numElements; i++) {
linkedList.get(i);
}
endTime = System.nanoTime();
System.out.println("LinkedList get: " + (endTime - startTime) / 1000000 + " ms");
// --- Removing elements from the beginning ---
startTime = System.nanoTime();
for (int i = 0; i < numElements; i++) {
arrayList.remove(0);
}
endTime = System.nanoTime();
System.out.println("ArrayList remove (beginning): " + (endTime - startTime) / 1000000 + " ms");
arrayList = new ArrayList<>();
for (int i = 0; i < numElements; i++) { arrayList.add(i);} //refill list to execute remove example below
linkedList = new LinkedList<>();
for (int i = 0; i < numElements; i++) { linkedList.add(i);} //refill list to execute remove example below
startTime = System.nanoTime();
for (int i = 0; i < numElements; i++) {
linkedList.remove(0);
}
endTime = System.nanoTime();
System.out.println("LinkedList remove (beginning): " + (endTime - startTime) / 1000000 + " ms");
}
}
Concepts Behind the Snippet
Real-Life Use Case Section
Best Practices
Interview Tip
Be prepared to discuss the time complexity of different operations for both `ArrayList` and `LinkedList`. Understand the underlying data structures and explain the trade-offs between them. Specifically, be ready to explain why inserting at the *beginning* of an `ArrayList` is slow, and why random access of a `LinkedList` is slow.
When to use them
Memory footprint
Alternatives
Pros
Cons
FAQ
-
Why is ArrayList faster for random access?
ArrayList uses a contiguous block of memory (an array). Given the index, the memory address of the element can be directly calculated, allowing constant-time (O(1)) access. -
Why is LinkedList faster for adding/removing at the beginning?
LinkedList uses a linked structure, so adding or removing at the beginning only requires updating a few pointers (the head and the next pointer of the new/previous first element). This takes constant time (O(1)). ArrayList, on the other hand, requires shifting all existing elements to make space (for adding) or fill the gap (for removing), which takes linear time (O(n)). -
When should I use LinkedList?
Use LinkedList when you need frequent insertions or deletions at the beginning or middle of the list and random access is not a primary concern. Examples include implementing a queue or a stack. -
Can I improve ArrayList's insertion performance?
Yes, if you know the size of the list in advance, you can specify the initial capacity in the constructor. This prevents the array from being resized multiple times as you add elements. Also, consider adding elements at the end whenever possible.