Java LinkedList
Doubly-linked list implementation for efficient insertions and deletions
🔗 What is LinkedList?
LinkedList is a doubly-linked list implementation that excels at frequent insertions and deletions but slower for random access compared to ArrayList.
// Creating and using LinkedList
import java.util.LinkedList;
LinkedList<String> queue = new LinkedList<>();
queue.addFirst("First"); // Add at beginning
queue.addLast("Last"); // Add at end
queue.add(1, "Middle"); // Add at specific position
System.out.println(queue);
Output:
[First, Middle, Last]
LinkedList Advantages
Fast Insertion
O(1) time for add/remove at ends
list.addFirst("item");
list.addLast("item");
Implements Queue
Perfect for queue and deque operations
list.offer("item");
list.poll();
No Capacity Limit
Grows without array resizing
// No capacity concerns
list.add("unlimited");
Bidirectional
Can traverse in both directions
list.descendingIterator();
🔹 LinkedList Specific Methods
Methods unique to LinkedList for efficient operations:
import java.util.*;
public class LinkedListMethods {
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<>();
// Adding at specific positions
list.addFirst("Start"); // Add at beginning
list.addLast("End"); // Add at end
list.add("Middle"); // Add at end (same as addLast)
System.out.println("After adding: " + list);
// Accessing first and last elements
System.out.println("First: " + list.getFirst());
System.out.println("Last: " + list.getLast());
// Peek methods (don't remove)
System.out.println("Peek first: " + list.peekFirst());
System.out.println("Peek last: " + list.peekLast());
// Queue operations
list.offer("Queued"); // Add to end (queue style)
System.out.println("After offer: " + list);
String polled = list.poll(); // Remove from beginning
System.out.println("Polled: " + polled);
System.out.println("After poll: " + list);
// Stack operations
list.push("Pushed"); // Add to beginning (stack style)
String popped = list.pop(); // Remove from beginning
System.out.println("Popped: " + popped);
System.out.println("Final: " + list);
}
}
Output:
After adding: [Start, End, Middle]
First: Start
Last: Middle
Peek first: Start
Peek last: Middle
After offer: [Start, End, Middle, Queued]
Polled: Start
After poll: [End, Middle, Queued]
Popped: Pushed
Final: [End, Middle, Queued]
🔹 LinkedList as Queue and Stack
LinkedList implements both Queue and Deque interfaces:
import java.util.*;
public class LinkedListAsQueueStack {
public static void main(String[] args) {
// Using LinkedList as Queue (FIFO - First In, First Out)
Queue<Integer> queue = new LinkedList<>();
queue.offer(1); // Add to rear
queue.offer(2);
queue.offer(3);
System.out.println("Queue: " + queue);
System.out.println("Poll: " + queue.poll()); // Remove from front
System.out.println("After poll: " + queue);
// Using LinkedList as Stack (LIFO - Last In, First Out)
Deque<String> stack = new LinkedList<>();
stack.push("Bottom"); // Add to top
stack.push("Middle");
stack.push("Top");
System.out.println("Stack: " + stack);
System.out.println("Pop: " + stack.pop()); // Remove from top
System.out.println("After pop: " + stack);
// Using as Deque (Double-ended queue)
Deque<Character> deque = new LinkedList<>();
deque.addFirst('A'); // Add to front
deque.addLast('Z'); // Add to rear
deque.addFirst('B'); // Add to front again
System.out.println("Deque: " + deque);
System.out.println("Remove first: " + deque.removeFirst());
System.out.println("Remove last: " + deque.removeLast());
System.out.println("Final deque: " + deque);
}
}
Output:
Queue: [1, 2, 3]
Poll: 1
After poll: [2, 3]
Stack: [Top, Middle, Bottom]
Pop: Top
After pop: [Middle, Bottom]
Deque: [B, A, Z]
Remove first: B
Remove last: Z
Final deque: [A]
🔹 ArrayList vs LinkedList
When to choose LinkedList over ArrayList:
Performance Comparison:
| Operation | ArrayList | LinkedList |
|---|---|---|
| Access by index | O(1) ✅ | O(n) ❌ |
| Add at beginning | O(n) ❌ | O(1) ✅ |
| Add at end | O(1) ✅ | O(1) ✅ |
| Memory usage | Lower ✅ | Higher ❌ |
// Choose ArrayList for:
List<String> arrayList = new ArrayList<>();
// - Frequent random access by index
// - More reading than inserting/deleting
// - Memory efficiency is important
// Choose LinkedList for:
List<String> linkedList = new LinkedList<>();
// - Frequent insertions/deletions at beginning or middle
// - Using as Queue or Stack
// - Don't need random access by index