Data Structures and Algorithms
Linked Lists
C-CAT
Linked Lists
What is a Linked List?
A Linked List is a collection of specially designed elements called nodes.
Node: An element that can be further divided into minimum 2 parts:
- Data — the value stored
- Address — address of the next element (next pointer)
head
|
v
[11|2000]-->[22|3000]-->[33|4000]-->[44|NULL]
1000 2000 3000 4000
How it differs from array:
- Elements not stored in contiguous memory
- Each node contains a pointer to the next node
- Dynamic size — grows and shrinks at runtime
Self-Referential Structure
A self-referential structure is a structure that has at least one member as a pointer pointing to the same type in which it is declared.
typedef struct node {
int data;
struct node *next; // pointer to same type <-- self-referential!
} node_t;
// Create a new node
node_t *p;
p = (node_t *) malloc(sizeof(node_t)); // allocate memory on heap
p->data = 42;
p->next = NULL;
Types of Linked Lists
| Type | Description |
|---|---|
| Singly Linear Linked List | Each node points to next; NULL at end |
| Singly Circular Linked List | Last node points back to first node |
| Doubly Linear Linked List | Each node has prev AND next pointer |
| Doubly Circular Linked List | Doubly + last node points to first |
Operations on Linked List
| Operation | Description |
|---|---|
| Add at first (addatfirst) | Insert new node before head |
| Add at last (addatlast) | Insert new node after tail |
| Add at position (addatpos) | Insert at specific position |
| Delete from first (delfromfirst) | Remove head node |
| Delete from last (delfromlast) | Remove tail node |
| Delete from position (delfrompos) | Remove node at specific position |
| Traverse | Visit each node exactly once |
| Search | Find node with given value |
| Sort | Arrange nodes in order |
| Merge | Combine two linked lists |
| Reverse | Reverse the order of nodes |
Singly Linear Linked List — C Implementation
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node *next;
} node_t;
// Create a new node
node_t *create_node(int value) {
node_t *p = (node_t *)
malloc(sizeof(node_t));
p->data = value;
p->next = NULL;
return p;
}
// Add at first
node_t *add_at_first(node_t *head, int value) {
node_t *new_node =
create_node(value);
new_node->next = head;
head = new_node;
return head;
}
// Add at last
node_t *add_at_last(node_t *head, int value) {
node_t *new_node =
create_node(value);
if (head == NULL) return new_node;
node_t *current = head;
while (current->next != NULL) {
current = current->next;
}
current->next =
new_node;
return head;
}
// Delete from first
node_t *del_from_first(node_t *head) {
if (head == NULL) {
printf("List is empty\n");
return NULL;
}
node_t *temp = head;
head =
head->next;
free(temp);
return head;
}
// Traverse
void traverse(node_t *head) {
node_t *current = head;
while (current !=
NULL) {
printf("%d -> ", current->data);
current = current->next;
}
printf("NULL\n");
}
// Search
int search(node_t *head, int target) {
node_t *current = head;
int
position = 0;
while (current != NULL) {
if (current->data == target) return
position;
current = current->next;
position++;
}
return -1; // not
found
}
// Reverse a linked list
node_t *reverse(node_t *head) {
node_t *prev = NULL;
node_t
*current = head;
node_t *next_node;
while (current != NULL) {
next_node
= current->next; // save next
current->next = prev; // reverse link
prev = current; // advance prev
current = next_node; // advance
current
}
return prev; // new head
}
int main() {
node_t *head = NULL;
head = add_at_last(head, 11);
head = add_at_last(head, 22);
head = add_at_last(head, 33);
head = add_at_first(head, 5);
printf("List: ");
traverse(head);
// Output: 5 -> 11 -> 22 -> 33 -> NULL
head = reverse(head);
printf("Reversed: ");
traverse(head);
// Output: 33 -> 22 -> 11 -> 5 -> NULL
return 0;
}
Doubly Linked List
typedef struct dnode {
int data;
struct dnode *prev; // pointer to previous node
struct dnode *next; // pointer to next node
} dnode_t;
NULL <-- [11] <--> [22] <--> [33] <--> [44] --> NULL
head tail
Advantages over SLL:
- Can traverse both forward and backward
- Deletion is O(1) if node pointer is given (no need to find prev)
Disadvantages:
- Extra memory per node (prev pointer)
- More complex insertion/deletion code
Advantages of Linked List
- Dynamic size — We can add/delete elements at runtime; actual number of elements can be increased or decreased
- Optimized memory usage — Memory allocated only when needed
Disadvantages of Linked List
- Pointer overhead — Each node has a member as pointer storing address of next element; memory for pointer is overhead against each element
- Cumbersome access — Accessing elements in linked list requires traversal from head; no random access
Linked List vs Array Comparison
| Feature | Array | Linked List |
|---|---|---|
| Memory | Contiguous | Non-contiguous |
| Size | Fixed (static) | Dynamic |
| Access | O(1) random | O(n) sequential |
| Insert/Delete (beginning) | O(n) | O(1) |
| Insert/Delete (end) | O(1) | O(n) without tail pointer |
| Memory efficiency | No pointer overhead | Pointer overhead |
| Cache performance | Good | Poor |
| Search | O(n) or O(log n) if sorted | O(n) |
Time Complexity of Linked List Operations
| Operation | Singly (no tail) | Singly (with tail) | Doubly |
|---|---|---|---|
| Insert at head | O(1) | O(1) | O(1) |
| Insert at tail | O(n) | O(1) | O(1) |
| Insert at middle | O(n) | O(n) | O(n) |
| Delete from head | O(1) | O(1) | O(1) |
| Delete from tail | O(n) | O(n) | O(1) |
| Search | O(n) | O(n) | O(n) |
Continue learning
Related notes
Definition of AI; Need of AI
Artificial Intelligence
Introduction to Data Engineering; Big Data — The 5 V's; Types of Data
Big Data and Data Engineering
Introduction to C Programming; C Program Structure; Data Types and Variables
C Programming
What Is a Computer?; Machine Cycle: Fetch–Decode–Execute; CPU Organization
Computer Architecture
Put this topic into timed practice
Open mock tests when you want full-exam pacing, or keep drilling in practice mode.