Arrays vs Linked Lists
Array Limitations
Arrays have fixed size which creates several problems:
- Fixed Size:
int A[100]- What if we need to store more than 100 elements? - Resizing is Expensive: To create a larger array
int B[150], we must:- Allocate new memory for B
- Copy all elements from A to B (takes
time) - Delete the old array A
- Memory Waste: If we only use 50 elements, 50 spaces are wasted
- Contiguous Memory Required: Need a continuous block of memory, which may not be available
Array vs Linked List Comparison
| Feature | Array | Linked List |
|---|---|---|
| Size | Fixed | Dynamic |
| Memory Allocation | Contiguous | Non-contiguous |
| Access Time | ||
| Insertion (at end) | ||
| Insertion (at beginning) | ||
| Memory Overhead | None | Extra space for pointers |
Linked List
A linked list is a linear data structure where elements (nodes) are stored in non-contiguous memory locations. Each node contains:
- Data: The value stored
- Pointer: Reference to the next node
Structure of a Linked List
Basic Linked List:
head
│
▼
┌────┬────┐ ┌────┬────┐ ┌────┬────┐ ┌────┬────┐
│ 8 │ ●─┼───→│ 20 │ ●─┼───→│ 30 │ ●─┼───→│ 40 │ X │
└────┴────┘ └────┴────┘ └────┴────┘ └────┴────┘
data next data next data next data NULL
- Each box represents a node
- Left part: data field
- Right part: next pointer (● = pointer, X = NULL)
- head: Pointer to the first node
- Last node’s next pointer is NULL
Insertion Operations
Example 1: Insert 35 between 30 and 40
Before:
head
│
▼
┌────┬────┐ ┌────┬────┐ ┌────┬────┐ ┌────┬────┐
│ 8 │ ●─┼───→│ 20 │ ●─┼───→│ 30 │ ●─┼───→│ 40 │ X │
└────┴────┘ └────┴────┘ └────┴────┘ └────┴────┘
After:
head
│
▼
┌────┬────┐ ┌────┬────┐ ┌────┬────┐ ┌────┬────┐ ┌────┬────┐
│ 8 │ ●─┼───→│ 20 │ ●─┼───→│ 30 │ ●─┼───→│ 35 │ ●─┼───→│ 40 │ X │
└────┴────┘ └────┴────┘ └────┴────┘ └────┴────┘ └────┴────┘
Steps:
- Create new node with data = 35
- Set new node’s next = node with 30’s next (points to 40)
- Set node with 30’s next = new node
Example 2: Insert 100 at the beginning
Before:
head
│
▼
┌────┬────┐ ┌────┬────┐ ┌────┬────┐
│ 8 │ ●─┼───→│ 20 │ ●─┼───→│ 30 │ X │
└────┴────┘ └────┴────┘ └────┴────┘
After:
head
│
▼
┌────┬────┐ ┌────┬────┐ ┌────┬────┐ ┌────┬────┐
│100 │ ●─┼───→│ 8 │ ●─┼───→│ 20 │ ●─┼───→│ 30 │ X │
└────┴────┘ └────┴────┘ └────┴────┘ └────┴────┘
Steps:
- Create new node with data = 100
- Set new node’s next = head (points to first node)
- Update head = new node
Implementation in C
Node Structure Definition
struct node {
int data; // Data field (can be any type)
struct node *next; // Pointer to next node
};Example with multiple fields:
struct student_node {
int rollno;
char name[20];
int marks;
struct student_node *next;
};Creating a New Node
Function to create and initialize a node:
struct node* createNode(int value) {
// Allocate memory for new node
struct node *newNode = (struct node*)malloc(sizeof(struct node));
// Check if memory allocation was successful
if (newNode == NULL) {
printf("Memory allocation failed\n");
return NULL;
}
// Initialize the node
newNode->data = value;
newNode->next = NULL;
return newNode;
}Basic Operations
1. Insert at Beginning
struct node* insertAtBeginning(struct node *head, int value) {
struct node *newNode = createNode(value);
newNode->next = head; // New node points to current head
head = newNode; // Update head to new node
return head;
}Time Complexity:
2. Insert at End
struct node* insertAtEnd(struct node *head, int value) {
struct node *newNode = createNode(value);
if (head == NULL) {
return newNode; // If list is empty, new node is the head
}
struct node *temp = head;
while (temp->next != NULL) { // Traverse to last node
temp = temp->next;
}
temp->next = newNode; // Link last node to new node
return head;
}Time Complexity:
3. Delete a Node
struct node* deleteNode(struct node *head, int value) {
if (head == NULL) return NULL;
// If head node holds the value to be deleted
if (head->data == value) {
struct node *temp = head;
head = head->next;
free(temp);
return head;
}
// Search for the node to be deleted
struct node *temp = head;
while (temp->next != NULL && temp->next->data != value) {
temp = temp->next;
}
// If value was found
if (temp->next != NULL) {
struct node *toDelete = temp->next;
temp->next = temp->next->next;
free(toDelete);
}
return head;
}Time Complexity:
Complexity Summary
| Operation | Array | Linked List |
|---|---|---|
| Access by index | ||
| Search | ||
| Insert at beginning | ||
| Insert at end | ||
| Delete at beginning | ||
| Delete at end |
Key Takeaways
- Linked Lists provide dynamic memory allocation
- No need for contiguous memory - nodes can be scattered in memory
- Efficient insertions/deletions at the beginning
- No wasted space - allocate only what you need
- Trade-off: Slower random access compared to arrays