Introduction to Linked Lists
A linked list is a linear data structure where elements are stored in nodes, each containing a data field and a pointer to the next node. Unlike arrays, linked lists are dynamic and can grow or shrink during runtime without memory wastage.
Linked List Architecture
Singly Linked List Structure ┌──────────┐ ┌──────────┐ ┌──────────┐ │ Data: 10 │ │ Data: 20 │ │ Data: 30 │ │ Next ────────>│ Next ────────>│ Next ────────> NULL └──────────┘ └──────────┘ └──────────┘ ^ ^ ^ | | | Head Tail (optional) Node Structure: ┌─────────────────┐ │ Data │ ├─────────────────┤ │ Next Pointer │ └─────────────────┘
Basic Node Structure
#include <stdio.h>
#include <stdlib.h>
// Node structure for singly linked list
struct Node {
int data; // Data stored in the node
struct Node* next; // Pointer to the next node
};
// Typedef for convenience
typedef struct Node Node;
Creating and Traversing Linked Lists
1. Creating a Simple Linked List
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* next;
} Node;
int main() {
// Create nodes
Node* head = NULL;
Node* second = NULL;
Node* third = NULL;
// Allocate memory for nodes in heap
head = (Node*)malloc(sizeof(Node));
second = (Node*)malloc(sizeof(Node));
third = (Node*)malloc(sizeof(Node));
// Assign data and link nodes
head->data = 10;
head->next = second;
second->data = 20;
second->next = third;
third->data = 30;
third->next = NULL; // Last node points to NULL
// Traverse and print the list
printf("Linked List: ");
Node* current = head;
while (current != NULL) {
printf("%d ", current->data);
current = current->next;
}
printf("\n");
// Free allocated memory
free(head);
free(second);
free(third);
return 0;
}
Output:
Linked List: 10 20 30
2. Function to Create a New Node
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* next;
} Node;
// Function to create a new node
Node* createNode(int data) {
Node* newNode = (Node*)malloc(sizeof(Node));
if (newNode == NULL) {
printf("Memory allocation failed!\n");
return NULL;
}
newNode->data = data;
newNode->next = NULL;
return newNode;
}
int main() {
// Create nodes using function
Node* head = createNode(10);
Node* second = createNode(20);
Node* third = createNode(30);
// Link nodes
head->next = second;
second->next = third;
// Print list
Node* current = head;
printf("Linked List: ");
while (current != NULL) {
printf("%d ", current->data);
current = current->next;
}
printf("\n");
// Free memory
current = head;
Node* next;
while (current != NULL) {
next = current->next;
free(current);
current = next;
}
return 0;
}
Basic Linked List Operations
1. Traversal
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* next;
} Node;
// Function to print the linked list
void printList(Node* head) {
printf("Linked List: ");
Node* current = head;
while (current != NULL) {
printf("%d ", current->data);
current = current->next;
}
printf("\n");
}
// Function to get length of linked list
int getLength(Node* head) {
int count = 0;
Node* current = head;
while (current != NULL) {
count++;
current = current->next;
}
return count;
}
// Recursive traversal
void printListRecursive(Node* head) {
if (head == NULL) {
printf("\n");
return;
}
printf("%d ", head->data);
printListRecursive(head->next);
}
int main() {
// Create a simple list: 10 -> 20 -> 30 -> NULL
Node* head = createNode(10);
head->next = createNode(20);
head->next->next = createNode(30);
printList(head);
printf("List length: %d\n", getLength(head));
printf("Recursive traversal: ");
printListRecursive(head);
// Free memory
Node* current = head;
while (current != NULL) {
Node* temp = current;
current = current->next;
free(temp);
}
return 0;
}
2. Insertion Operations
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* next;
} Node;
// Insert at beginning
Node* insertAtBeginning(Node* head, int data) {
Node* newNode = createNode(data);
newNode->next = head;
return newNode; // New head
}
// Insert at end
Node* insertAtEnd(Node* head, int data) {
Node* newNode = createNode(data);
if (head == NULL) {
return newNode;
}
Node* current = head;
while (current->next != NULL) {
current = current->next;
}
current->next = newNode;
return head;
}
// Insert at position (0-based index)
Node* insertAtPosition(Node* head, int data, int position) {
if (position < 0) {
printf("Invalid position!\n");
return head;
}
if (position == 0) {
return insertAtBeginning(head, data);
}
Node* newNode = createNode(data);
Node* current = head;
// Traverse to position-1
for (int i = 0; i < position - 1 && current != NULL; i++) {
current = current->next;
}
if (current == NULL) {
printf("Position out of range!\n");
free(newNode);
return head;
}
newNode->next = current->next;
current->next = newNode;
return head;
}
// Insert after a given node
void insertAfter(Node* prevNode, int data) {
if (prevNode == NULL) {
printf("Previous node cannot be NULL\n");
return;
}
Node* newNode = createNode(data);
newNode->next = prevNode->next;
prevNode->next = newNode;
}
int main() {
Node* head = NULL;
// Insert at beginning
head = insertAtBeginning(head, 30);
head = insertAtBeginning(head, 20);
head = insertAtBeginning(head, 10);
printf("After inserting at beginning: ");
printList(head); // 10 20 30
// Insert at end
head = insertAtEnd(head, 40);
head = insertAtEnd(head, 50);
printf("After inserting at end: ");
printList(head); // 10 20 30 40 50
// Insert at position
head = insertAtPosition(head, 25, 2);
printf("After inserting 25 at position 2: ");
printList(head); // 10 20 25 30 40 50
// Insert after a node
insertAfter(head->next, 22); // After second node (20)
printf("After inserting 22 after 20: ");
printList(head); // 10 20 22 25 30 40 50
return 0;
}
3. Deletion Operations
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* next;
} Node;
// Delete first node
Node* deleteFirst(Node* head) {
if (head == NULL) {
printf("List is empty\n");
return NULL;
}
Node* temp = head;
head = head->next;
free(temp);
return head;
}
// Delete last node
Node* deleteLast(Node* head) {
if (head == NULL) {
printf("List is empty\n");
return NULL;
}
if (head->next == NULL) {
free(head);
return NULL;
}
Node* current = head;
while (current->next->next != NULL) {
current = current->next;
}
free(current->next);
current->next = NULL;
return head;
}
// Delete node at position
Node* deleteAtPosition(Node* head, int position) {
if (head == NULL || position < 0) {
return head;
}
if (position == 0) {
return deleteFirst(head);
}
Node* current = head;
for (int i = 0; i < position - 1 && current != NULL; i++) {
current = current->next;
}
if (current == NULL || current->next == NULL) {
printf("Position out of range\n");
return head;
}
Node* temp = current->next;
current->next = temp->next;
free(temp);
return head;
}
// Delete by value (first occurrence)
Node* deleteByValue(Node* head, int value) {
if (head == NULL) {
return NULL;
}
// If head node contains the value
if (head->data == value) {
Node* temp = head;
head = head->next;
free(temp);
return head;
}
Node* current = head;
while (current->next != NULL && current->next->data != value) {
current = current->next;
}
if (current->next == NULL) {
printf("Value %d not found in list\n", value);
return head;
}
Node* temp = current->next;
current->next = temp->next;
free(temp);
return head;
}
int main() {
Node* head = NULL;
// Create a list: 10 -> 20 -> 30 -> 40 -> 50
for (int i = 50; i >= 10; i -= 10) {
head = insertAtBeginning(head, i);
}
printf("Original list: ");
printList(head); // 10 20 30 40 50
// Delete first
head = deleteFirst(head);
printf("After deleting first: ");
printList(head); // 20 30 40 50
// Delete last
head = deleteLast(head);
printf("After deleting last: ");
printList(head); // 20 30 40
// Delete at position
head = deleteAtPosition(head, 1);
printf("After deleting at position 1: ");
printList(head); // 20 40
// Delete by value
head = deleteByValue(head, 20);
printf("After deleting 20: ");
printList(head); // 40
return 0;
}
4. Search Operations
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct Node {
int data;
struct Node* next;
} Node;
// Search for a value (iterative)
bool searchIterative(Node* head, int key) {
Node* current = head;
while (current != NULL) {
if (current->data == key) {
return true;
}
current = current->next;
}
return false;
}
// Search for a value (recursive)
bool searchRecursive(Node* head, int key) {
if (head == NULL) {
return false;
}
if (head->data == key) {
return true;
}
return searchRecursive(head->next, key);
}
// Get node at position
Node* getNodeAtPosition(Node* head, int position) {
Node* current = head;
int count = 0;
while (current != NULL && count < position) {
current = current->next;
count++;
}
return current;
}
// Get middle node (Floyd's algorithm)
Node* getMiddleNode(Node* head) {
if (head == NULL) {
return NULL;
}
Node* slow = head;
Node* fast = head;
while (fast != NULL && fast->next != NULL) {
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
// Count occurrences of a value
int countOccurrences(Node* head, int key) {
int count = 0;
Node* current = head;
while (current != NULL) {
if (current->data == key) {
count++;
}
current = current->next;
}
return count;
}
int main() {
Node* head = NULL;
// Create list: 10 -> 20 -> 30 -> 20 -> 40 -> 20 -> 50
int values[] = {10, 20, 30, 20, 40, 20, 50};
for (int i = 6; i >= 0; i--) {
head = insertAtBeginning(head, values[i]);
}
printList(head);
// Search operations
int searchValue = 20;
printf("\n=== Search Operations ===\n");
printf("Searching for %d (iterative): %s\n",
searchValue, searchIterative(head, searchValue) ? "Found" : "Not found");
printf("Searching for %d (recursive): %s\n",
searchValue, searchRecursive(head, searchValue) ? "Found" : "Not found");
printf("Node at position 3: %d\n", getNodeAtPosition(head, 3)->data);
Node* middle = getMiddleNode(head);
printf("Middle node: %d\n", middle->data);
printf("Occurrences of 20: %d\n", countOccurrences(head, 20));
return 0;
}
Advanced Operations
1. Reverse a Linked List
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* next;
} Node;
// Reverse linked list (iterative)
Node* reverseIterative(Node* head) {
Node *prev = NULL;
Node *current = head;
Node *next = NULL;
while (current != NULL) {
next = current->next; // Store next node
current->next = prev; // Reverse current node's pointer
prev = current; // Move prev one step forward
current = next; // Move current one step forward
}
return prev; // New head
}
// Reverse linked list (recursive)
Node* reverseRecursive(Node* head) {
if (head == NULL || head->next == NULL) {
return head;
}
Node* rest = reverseRecursive(head->next);
head->next->next = head;
head->next = NULL;
return rest;
}
int main() {
Node* head = NULL;
// Create list: 1 -> 2 -> 3 -> 4 -> 5
for (int i = 5; i >= 1; i--) {
head = insertAtBeginning(head, i);
}
printf("Original list: ");
printList(head);
// Reverse iteratively
head = reverseIterative(head);
printf("After iterative reverse: ");
printList(head);
// Reverse back recursively
head = reverseRecursive(head);
printf("After recursive reverse: ");
printList(head);
return 0;
}
2. Detect Loop in Linked List
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct Node {
int data;
struct Node* next;
} Node;
// Detect loop using Floyd's Cycle Detection
bool detectLoop(Node* head) {
Node* slow = head;
Node* fast = head;
while (slow && fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) {
return true; // Loop detected
}
}
return false;
}
// Find start of loop
Node* findLoopStart(Node* head) {
Node* slow = head;
Node* fast = head;
bool loopExists = false;
// Detect loop
while (slow && fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) {
loopExists = true;
break;
}
}
if (!loopExists) {
return NULL;
}
// Find loop start
slow = head;
while (slow != fast) {
slow = slow->next;
fast = fast->next;
}
return slow;
}
// Remove loop
void removeLoop(Node* head) {
Node* loopStart = findLoopStart(head);
if (loopStart == NULL) {
return;
}
Node* current = loopStart;
while (current->next != loopStart) {
current = current->next;
}
current->next = NULL; // Break the loop
}
int main() {
// Create a list with a loop
Node* head = createNode(1);
head->next = createNode(2);
head->next->next = createNode(3);
head->next->next->next = createNode(4);
head->next->next->next->next = createNode(5);
head->next->next->next->next->next = head->next; // Create loop (5 -> 2)
printf("Loop detected: %s\n", detectLoop(head) ? "Yes" : "No");
Node* loopStart = findLoopStart(head);
if (loopStart) {
printf("Loop starts at node with value: %d\n", loopStart->data);
}
removeLoop(head);
printf("After removing loop: %s\n", detectLoop(head) ? "Yes" : "No");
printList(head); // Should print: 1 2 3 4 5
return 0;
}
3. Find Nth Node from End
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* next;
} Node;
// Find nth node from end (using two pointers)
Node* findNthFromEnd(Node* head, int n) {
if (head == NULL || n <= 0) {
return NULL;
}
Node* main_ptr = head;
Node* ref_ptr = head;
// Move ref_ptr n steps ahead
for (int count = 1; count <= n; count++) {
if (ref_ptr == NULL) {
printf("List has fewer than %d nodes\n", n);
return NULL;
}
ref_ptr = ref_ptr->next;
}
// Move both pointers until ref_ptr reaches end
while (ref_ptr != NULL) {
main_ptr = main_ptr->next;
ref_ptr = ref_ptr->next;
}
return main_ptr;
}
// Find nth node from end (using length)
Node* findNthFromEndLength(Node* head, int n) {
int length = getLength(head);
if (n > length || n <= 0) {
return NULL;
}
int position = length - n;
Node* current = head;
for (int i = 0; i < position; i++) {
current = current->next;
}
return current;
}
int main() {
Node* head = NULL;
// Create list: 10 -> 20 -> 30 -> 40 -> 50 -> 60 -> 70
for (int i = 70; i >= 10; i -= 10) {
head = insertAtBeginning(head, i);
}
printList(head);
int n = 3;
Node* nthFromEnd = findNthFromEnd(head, n);
if (nthFromEnd) {
printf("%dth node from end: %d\n", n, nthFromEnd->data);
}
n = 5;
nthFromEnd = findNthFromEndLength(head, n);
if (nthFromEnd) {
printf("%dth node from end: %d\n", n, nthFromEnd->data);
}
return 0;
}
Complete Linked List Implementation
linkedlist.h
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct Node {
int data;
struct Node* next;
} Node;
// Basic operations
Node* createNode(int data);
void printList(Node* head);
int getLength(Node* head);
bool isEmpty(Node* head);
void freeList(Node* head);
// Insertion operations
Node* insertAtBeginning(Node* head, int data);
Node* insertAtEnd(Node* head, int data);
Node* insertAtPosition(Node* head, int data, int position);
void insertAfter(Node* prevNode, int data);
// Deletion operations
Node* deleteFirst(Node* head);
Node* deleteLast(Node* head);
Node* deleteAtPosition(Node* head, int position);
Node* deleteByValue(Node* head, int value);
// Search operations
bool searchIterative(Node* head, int key);
bool searchRecursive(Node* head, int key);
Node* getNodeAtPosition(Node* head, int position);
int countOccurrences(Node* head, int key);
// Advanced operations
Node* reverseIterative(Node* head);
Node* reverseRecursive(Node* head);
bool detectLoop(Node* head);
Node* findLoopStart(Node* head);
void removeLoop(Node* head);
Node* findNthFromEnd(Node* head, int n);
Node* getMiddleNode(Node* head);
Node* mergeSortedLists(Node* head1, Node* head2);
#endif
linkedlist.c
#include "linkedlist.h"
// Create a new node
Node* createNode(int data) {
Node* newNode = (Node*)malloc(sizeof(Node));
if (newNode == NULL) {
printf("Memory allocation failed!\n");
return NULL;
}
newNode->data = data;
newNode->next = NULL;
return newNode;
}
// Print the linked list
void printList(Node* head) {
printf("Linked List: ");
Node* current = head;
while (current != NULL) {
printf("%d ", current->data);
current = current->next;
}
printf("\n");
}
// Get length of linked list
int getLength(Node* head) {
int count = 0;
Node* current = head;
while (current != NULL) {
count++;
current = current->next;
}
return count;
}
// Check if list is empty
bool isEmpty(Node* head) {
return head == NULL;
}
// Free entire list
void freeList(Node* head) {
Node* current = head;
Node* next;
while (current != NULL) {
next = current->next;
free(current);
current = next;
}
}
// Insert at beginning
Node* insertAtBeginning(Node* head, int data) {
Node* newNode = createNode(data);
if (newNode == NULL) return head;
newNode->next = head;
return newNode;
}
// Insert at end
Node* insertAtEnd(Node* head, int data) {
Node* newNode = createNode(data);
if (newNode == NULL) return head;
if (head == NULL) {
return newNode;
}
Node* current = head;
while (current->next != NULL) {
current = current->next;
}
current->next = newNode;
return head;
}
// Insert at position
Node* insertAtPosition(Node* head, int data, int position) {
if (position < 0) {
printf("Invalid position!\n");
return head;
}
if (position == 0) {
return insertAtBeginning(head, data);
}
Node* newNode = createNode(data);
if (newNode == NULL) return head;
Node* current = head;
for (int i = 0; i < position - 1 && current != NULL; i++) {
current = current->next;
}
if (current == NULL) {
printf("Position out of range!\n");
free(newNode);
return head;
}
newNode->next = current->next;
current->next = newNode;
return head;
}
// Insert after a given node
void insertAfter(Node* prevNode, int data) {
if (prevNode == NULL) {
printf("Previous node cannot be NULL\n");
return;
}
Node* newNode = createNode(data);
if (newNode == NULL) return;
newNode->next = prevNode->next;
prevNode->next = newNode;
}
// Delete first node
Node* deleteFirst(Node* head) {
if (head == NULL) {
printf("List is empty\n");
return NULL;
}
Node* temp = head;
head = head->next;
free(temp);
return head;
}
// Delete last node
Node* deleteLast(Node* head) {
if (head == NULL) {
printf("List is empty\n");
return NULL;
}
if (head->next == NULL) {
free(head);
return NULL;
}
Node* current = head;
while (current->next->next != NULL) {
current = current->next;
}
free(current->next);
current->next = NULL;
return head;
}
// Delete node at position
Node* deleteAtPosition(Node* head, int position) {
if (head == NULL || position < 0) {
return head;
}
if (position == 0) {
return deleteFirst(head);
}
Node* current = head;
for (int i = 0; i < position - 1 && current != NULL; i++) {
current = current->next;
}
if (current == NULL || current->next == NULL) {
printf("Position out of range\n");
return head;
}
Node* temp = current->next;
current->next = temp->next;
free(temp);
return head;
}
// Delete by value (first occurrence)
Node* deleteByValue(Node* head, int value) {
if (head == NULL) {
return NULL;
}
if (head->data == value) {
Node* temp = head;
head = head->next;
free(temp);
return head;
}
Node* current = head;
while (current->next != NULL && current->next->data != value) {
current = current->next;
}
if (current->next == NULL) {
printf("Value %d not found in list\n", value);
return head;
}
Node* temp = current->next;
current->next = temp->next;
free(temp);
return head;
}
// Search for a value (iterative)
bool searchIterative(Node* head, int key) {
Node* current = head;
while (current != NULL) {
if (current->data == key) {
return true;
}
current = current->next;
}
return false;
}
// Search for a value (recursive)
bool searchRecursive(Node* head, int key) {
if (head == NULL) {
return false;
}
if (head->data == key) {
return true;
}
return searchRecursive(head->next, key);
}
// Get node at position
Node* getNodeAtPosition(Node* head, int position) {
Node* current = head;
int count = 0;
while (current != NULL && count < position) {
current = current->next;
count++;
}
return current;
}
// Count occurrences of a value
int countOccurrences(Node* head, int key) {
int count = 0;
Node* current = head;
while (current != NULL) {
if (current->data == key) {
count++;
}
current = current->next;
}
return count;
}
// Reverse linked list (iterative)
Node* reverseIterative(Node* head) {
Node *prev = NULL;
Node *current = head;
Node *next = NULL;
while (current != NULL) {
next = current->next;
current->next = prev;
prev = current;
current = next;
}
return prev;
}
// Reverse linked list (recursive)
Node* reverseRecursive(Node* head) {
if (head == NULL || head->next == NULL) {
return head;
}
Node* rest = reverseRecursive(head->next);
head->next->next = head;
head->next = NULL;
return rest;
}
// Detect loop using Floyd's Cycle Detection
bool detectLoop(Node* head) {
Node* slow = head;
Node* fast = head;
while (slow && fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) {
return true;
}
}
return false;
}
// Find start of loop
Node* findLoopStart(Node* head) {
Node* slow = head;
Node* fast = head;
bool loopExists = false;
while (slow && fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) {
loopExists = true;
break;
}
}
if (!loopExists) {
return NULL;
}
slow = head;
while (slow != fast) {
slow = slow->next;
fast = fast->next;
}
return slow;
}
// Remove loop
void removeLoop(Node* head) {
Node* loopStart = findLoopStart(head);
if (loopStart == NULL) {
return;
}
Node* current = loopStart;
while (current->next != loopStart) {
current = current->next;
}
current->next = NULL;
}
// Find nth node from end
Node* findNthFromEnd(Node* head, int n) {
if (head == NULL || n <= 0) {
return NULL;
}
Node* main_ptr = head;
Node* ref_ptr = head;
for (int count = 1; count <= n; count++) {
if (ref_ptr == NULL) {
printf("List has fewer than %d nodes\n", n);
return NULL;
}
ref_ptr = ref_ptr->next;
}
while (ref_ptr != NULL) {
main_ptr = main_ptr->next;
ref_ptr = ref_ptr->next;
}
return main_ptr;
}
// Get middle node
Node* getMiddleNode(Node* head) {
if (head == NULL) {
return NULL;
}
Node* slow = head;
Node* fast = head;
while (fast != NULL && fast->next != NULL) {
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
// Merge two sorted lists
Node* mergeSortedLists(Node* head1, Node* head2) {
if (head1 == NULL) return head2;
if (head2 == NULL) return head1;
Node* result = NULL;
if (head1->data <= head2->data) {
result = head1;
result->next = mergeSortedLists(head1->next, head2);
} else {
result = head2;
result->next = mergeSortedLists(head1, head2->next);
}
return result;
}
Time Complexity Analysis
| Operation | Time Complexity | Description |
|---|---|---|
| Access by index | O(n) | Must traverse from head |
| Insert at beginning | O(1) | Update head pointer |
| Insert at end | O(n) | Traverse to last node |
| Insert at position | O(n) | Traverse to position |
| Delete at beginning | O(1) | Update head pointer |
| Delete at end | O(n) | Traverse to second last |
| Delete at position | O(n) | Traverse to position |
| Search | O(n) | Linear search |
| Reverse | O(n) | Traverse once |
| Get length | O(n) | Traverse entire list |
| Get middle | O(n) | Two-pointer technique |
Space Complexity Analysis
| Operation | Space Complexity | Description |
|---|---|---|
| Node creation | O(n) | n nodes in list |
| List reversal (iterative) | O(1) | Constant extra space |
| List reversal (recursive) | O(n) | Call stack |
| Merge sort | O(1) | In-place merging |
| Recursive operations | O(n) | Call stack depth |
Common Applications
| Application | Description | Example |
|---|---|---|
| Dynamic memory management | Grow/shrink as needed | Memory pools |
| Undo functionality | Store operation history | Text editors |
| Symbol tables | Compiler symbol management | Hash table chaining |
| Polynomial arithmetic | Store coefficients | Mathematical software |
| Sparse matrices | Efficient storage | Scientific computing |
| Task scheduling | Process queues | Operating systems |
| Browser history | Navigation | Web browsers |
Advantages and Disadvantages
Advantages
- Dynamic size - Can grow/shrink at runtime
- Efficient insertion/deletion - O(1) at beginning
- No memory wastage - Allocates exactly what's needed
- Flexible implementation - Easy to implement complex structures
Disadvantages
- Sequential access - No random access
- Extra memory - Stores pointer with each element
- Cache unfriendly - Nodes scattered in memory
- Traversal overhead - Must traverse from head for access
Conclusion
Linked lists are fundamental data structures that provide dynamic memory allocation and efficient insertion/deletion operations. Key takeaways:
- Dynamic nature - Lists can grow/shrink as needed
- Node structure - Each node contains data and pointer to next node
- Basic operations - Insert, delete, search, traverse
- Advanced operations - Reverse, detect loops, merge
- Time-space tradeoff - Flexibility comes with overhead
When to Use Linked Lists
- When size is unknown at compile time
- Frequent insertions/deletions at beginning
- Implementing stacks and queues
- Memory-constrained environments
- When random access is not required
When NOT to Use Linked Lists
- Frequent random access needed
- Memory overhead is critical
- Better cache performance required
- Simple array is sufficient
Linked lists are essential for understanding dynamic data structures and are widely used in system programming, algorithm implementation, and as building blocks for more complex data structures.