A linked list is a fundamental data structure that stores a collection of elements in a linear order. Unlike arrays, linked lists do not store elements in contiguous memory locations, which allows for more flexible memory usage and easier insertion and deletion operations. Java provides a standard implementation of linked lists through the LinkedList class in the Java Collections Framework, but understanding the inner workings of a linked list helps developers better grasp its use cases and limitations. This article delves deep into linked lists, providing a comprehensive overview of their structure, types, implementation, and use in Java.
A linked list consists of nodes where each node contains data and a reference (or link) to the next node in the sequence. The last node’s reference points to null, marking the end of the list. The structure of a linked list can be summarized as:
null.Let’s explore how to implement a singly linked list in Java. We’ll create a Node class for the list elements and a LinkedList class to manage the list operations.
class Node {
int data;
Node next;
Node(int data) {
this.data = data;
this.next = null;
}
}
class SinglyLinkedList {
private Node head;
// Add an element at the front of the list
public void addFirst(int data) {
Node newNode = new Node(data);
newNode.next = head;
head = newNode;
}
// Add an element at the end of the list
public void addLast(int data) {
Node newNode = new Node(data);
if (head == null) {
head = newNode;
return;
}
Node temp = head;
while (temp.next != null) {
temp = temp.next;
}
temp.next = newNode;
}
// Delete the first occurrence of a given value
public void delete(int data) {
if (head == null) return;
if (head.data == data) {
head = head.next;
return;
}
Node temp = head;
while (temp.next != null && temp.next.data != data) {
temp = temp.next;
}
if (temp.next == null) return;
temp.next = temp.next.next;
}
// Print all the elements in the list
public void printList() {
Node temp = head;
while (temp != null) {
System.out.print(temp.data + " ");
temp = temp.next;
}
System.out.println();
}
}
Let’s use this implementation to test a basic singly linked list in Java.
public class LinkedListTest {
public static void main(String[] args) {
SinglyLinkedList list = new SinglyLinkedList();
list.addFirst(10);
list.addFirst(20);
list.addLast(30);
list.addLast(40);
System.out.print("List elements: ");
list.printList(); // Output: 20 10 30 40
list.delete(10);
System.out.print("After deletion: ");
list.printList(); // Output: 20 30 40
}
}
A doubly linked list requires each node to store references to both the previous and next nodes.
class DoublyNode {
int data;
DoublyNode prev, next;
DoublyNode(int data) {
this.data = data;
this.prev = this.next = null;
}
}
class DoublyLinkedList {
private DoublyNode head;
// Add an element at the front of the list
public void addFirst(int data) {
DoublyNode newNode = new DoublyNode(data);
newNode.next = head;
if (head != null) {
head.prev = newNode;
}
head = newNode;
}
// Add an element at the end of the list
public void addLast(int data) {
DoublyNode newNode = new DoublyNode(data);
if (head == null) {
head = newNode;
return;
}
DoublyNode temp = head;
while (temp.next != null) {
temp = temp.next;
}
temp.next = newNode;
newNode.prev = temp;
}
// Delete the first occurrence of a given value
public void delete(int data) {
if (head == null) return;
if (head.data == data) {
head = head.next;
if (head != null) {
head.prev = null;
}
return;
}
DoublyNode temp = head;
while (temp != null && temp.data != data) {
temp = temp.next;
}
if (temp == null) return;
if (temp.next != null) {
temp.next.prev = temp.prev;
}
if (temp.prev != null) {
temp.prev.next = temp.next;
}
}
// Print all the elements in the list
public void printList() {
DoublyNode temp = head;
while (temp != null) {
System.out.print(temp.data + " ");
temp = temp.next;
}
System.out.println();
}
}
Let’s create a test to demonstrate the operations of the doubly linked list.
public class DoublyLinkedListTest {
public static void main(String[] args) {
DoublyLinkedList list = new DoublyLinkedList();
list.addFirst(10);
list.addFirst(20);
list.addLast(30);
list.addLast(40);
System.out.print("List elements: ");
list.printList(); // Output: 20 10 30 40
list.delete(10);
System.out.print("After deletion: ");
list.printList(); // Output: 20 30 40
}
}