0% found this document useful (0 votes)
3 views

Linked List

The document provides a comprehensive overview of linked lists, focusing on singly linked lists, doubly linked lists, and circular linked lists. It details their characteristics, time and space complexities, algorithms for insertion and deletion, and includes pseudocode and C code implementations. The document emphasizes the advantages of linked lists over arrays, particularly in terms of dynamic memory allocation and efficient insertion/deletion operations.

Uploaded by

labiba.u.t.333
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

Linked List

The document provides a comprehensive overview of linked lists, focusing on singly linked lists, doubly linked lists, and circular linked lists. It details their characteristics, time and space complexities, algorithms for insertion and deletion, and includes pseudocode and C code implementations. The document emphasizes the advantages of linked lists over arrays, particularly in terms of dynamic memory allocation and efficient insertion/deletion operations.

Uploaded by

labiba.u.t.333
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 25

Linked List

Singly Linked List


A Singly Linked List is a linear data structure where each element (node) contains
two parts: the data and a reference (or link) to the next node in the sequence. Unlike
arrays, linked lists do not store elements in contiguous memory locations. The nodes
are scattered in memory, and each node points to the next one, forming a chain-like
structure.

Characteristics of Singly Linked List:


Characteristic Description
Type Linear Data Structure
Memory Usage Dynamic (memory allocated as needed, unlike arrays)
Sequential access (to access the nth element, traversal from the
Access
head node is required)
More efficient for insertion/deletion, especially in the middle of
Insertion/Deletion
the list, compared to arrays
Search
O(n), as it requires traversal of the list to find an element
Complexity
Yes, the linked list does not require extra space apart from the
In-place
nodes themselves.

Time Complexity:
Operation Time Complexity
Insertion at Beginning O(1)
Insertion at End O(n)
Insertion in Middle O(n)
Deletion at Beginning O(1)
Deletion at End O(n)
Deletion in Middle O(n)
Search O(n)
Traversal O(n)

Space Complexity:
The space complexity of a linked list is O(n), where n is the number of nodes in the
list. Each node stores one element of data and a reference to the next node, so
memory usage grows linearly with the number of elements.
Algorithm :
Insertion at Beginning:
Step 1 : Create a new node.
Step 2 : Point the new node’s next reference to the current head.
Step 3 : Update the head to point to the new node.

Insertion at End:
Step 1 : Traverse to the last node.
Step 2 : Create a new node and point the current last node’s next to the new node.

Insertion in Middle:
Step 1 : Traverse the list to the desired position.
Step 2 : Insert the new node at that position by adjusting the pointers of the
previous and next nodes.

Deletion at Beginning:
Update the head to point to the second node.

Deletion at End:
Step 1 : Traverse the list to the second last node.
Step 2 : Update the second last node’s next to NULL, effectively removing the last
node.

Deletion in Middle:
Step 1 : Traverse to the desired node.
Step 2 : Adjust the previous node’s next reference to point to the node after the one
being deleted.

Search for an Element:


Traverse the list, comparing each node’s data to the target.

Traversal:
Traverse through the list and print all elements.

Print the List:


Print each element of the list from the head to the last node.
Pseudocode:
Function InsertAtBeginning(value):
Create a new node with data = value
new_node.next = head
head = new_node

Function InsertAtEnd(value):
Create a new node with data = value
If head is NULL:
head = new_node
return
Traverse to the last node
last_node.next = new_node

Function InsertInMiddle(position, value):


Create a new node with data = value
Traverse to the node before the position
new_node.next = current_node.next
current_node.next = new_node

Function DeleteAtBeginning():
If head is NULL:
Print "List is Empty"
return
head = head.next

Function DeleteAtEnd():
If head is NULL:
Print "List is Empty"
return
Traverse to the second last node
second_last.next = NULL

Function DeleteAtMiddle(position):
If head is NULL:
Print "List is Empty"
return
Traverse to the node before the position
current_node.next = current_node.next.next

Function Search(value):
Traverse the list and compare each node’s data with value
Return the position if found, otherwise -1

Function PrintList():
Traverse the list and print each node’s data
Singly Linked List Code:
#include <stdio.h>
#include <stdlib.h>

// Node structure
struct Node {
int data;
struct Node* next;
};

// Head of the list


struct Node* head = NULL;

// Function to insert at the beginning


void insertAtBeginning(int value) {
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
new_node->data = value;
new_node->next = head;
head = new_node;
printf("Inserted %d at the beginning\n", value);
}

// Function to insert at the end


void insertAtEnd(int value) {
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
struct Node* temp = head;
new_node->data = value;
new_node->next = NULL;

if (head == NULL) {
head = new_node;
printf("Inserted %d at the end\n", value);
return;
}

while (temp->next != NULL) {


temp = temp->next;
}
temp->next = new_node;
printf("Inserted %d at the end\n", value);
}

// Function to insert at a specific position


void insertAtMiddle(int position, int value) {
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
struct Node* temp = head;
int i;
new_node->data = value;

for (i = 1; temp != NULL && i < position; i++) {


temp = temp->next;
}

if (temp == NULL) {
printf("Position exceeds the length of the list.\n");
return;
}

new_node->next = temp->next;
temp->next = new_node;

printf("Inserted %d at position %d\n", value, position);


}

// Function to delete from the beginning


void deleteAtBeginning() {
if (head == NULL) {
printf("List is Empty\n");
return;
}

struct Node* temp = head;


head = head->next;
free(temp);

printf("Deleted the first node\n");


}

// Function to delete from the end


void deleteAtEnd() {
if (head == NULL) {
printf("List is Empty\n");
return;
}

struct Node* temp = head;


struct Node* prev = NULL;

while (temp->next != NULL) {


prev = temp;
temp = temp->next;
}
if (prev != NULL) {
prev->next = NULL;
} else {
head = NULL;
}

free(temp);

printf("Deleted the last node\n");


}

// Function to delete at a specific position


void deleteAtMiddle(int position) {
if (head == NULL) {
printf("List is Empty\n");
return;
}

struct Node* temp = head;


struct Node* prev = NULL;
int i;

for (i = 1; temp != NULL && i < position; i++) {


prev = temp;
temp = temp->next;
}

if (temp == NULL) {
printf("Position exceeds the length of the list.\n");
return;
}

prev->next = temp->next;
free(temp);

printf("Deleted node at position %d\n", position);


}

// Function to search for a value


void search(int value) {
struct Node* temp = head;
int position = 1;

while (temp != NULL) {


if (temp->data == value) {
printf("Found %d at position %d\n", value, position);
return;
}
position++;
temp = temp->next;
}

printf("%d not found in the list\n", value);


}

// Function to print the list


void printList() {
struct Node* temp = head;

if (temp == NULL) {
printf("List is Empty\n");
return;
}

printf("List: ");
while (temp != NULL) {
printf("%d -> ", temp->data);
temp = temp->next;
}
printf("NULL\n");
}

int main() {
int choice, value, position;

while (1) {
printf("\nLinked List Menu:\n");
printf("1. Insert at Beginning\n");
printf("2. Insert at End\n");
printf("3. Insert at Middle\n");
printf("4. Delete from Beginning\n");
printf("5. Delete from End\n");
printf("6. Delete from Middle\n");
printf("7. Search for an Element\n");
printf("8. Print the List\n");
printf("9. Exit\n");
printf("Enter your choice: ");
scanf("%d", &choice);

if (choice == 1) {
printf("Enter value to insert at the beginning: ");
scanf("%d", &value);
insertAtBeginning(value);
} else if (choice == 2) {
printf("Enter value to insert at the end: ");
scanf("%d", &value);
insertAtEnd(value);
} else if (choice == 3) {
printf("Enter position to insert at: ");
scanf("%d", &position);
printf("Enter value to insert: ");
scanf("%d", &value);
insertAtMiddle(position, value);
} else if (choice == 4) {
deleteAtBeginning();
} else if (choice == 5) {
deleteAtEnd();
} else if (choice == 6) {
printf("Enter position to delete from: ");
scanf("%d", &position);
deleteAtMiddle(position);
} else if (choice == 7) {
printf("Enter value to search: ");
scanf("%d", &value);
search(value);
} else if (choice == 8) {
printList();
} else if (choice == 9) {
printf("Exiting the program.\n");
break;
} else {
printf("Invalid choice! Please try again.\n");
}
}

return 0;
}
Doubly Linked List
A Doubly Linked List (DLL) is a type of linked list where each node contains three
parts: The data, A pointer to the next node, A pointer to the previous node.
This structure allows bidirectional traversal, i.e., both forward and backward
movement through the list.

Characteristics of Doubly Linked List


Characteristic Description
Type Non-linear, dynamic data structure
Nodes Each node contains data, prev and next
Traversal Bidirectional (forward and backward)
Dynamic Yes (can grow/shrink during runtime)
Memory More memory required (extra pointer per node)
Complexity
O(n) – Linear time to access elements
(Access)
Efficient Insertion and deletion are efficient, especially if position is
Operations known
Head and Tail Usually managed to allow operations from both ends

Time Complexities
Operation Time Complexity
Traversal O(n)
Insertion (front) O(1)
Insertion (end) O(1) if tail used, else O(n)
Insertion (middle) O(n)
Deletion (front) O(1)
Deletion (end) O(1) if tail used, else O(n)
Deletion (middle) O(n)
Search O(n)

Space Complexity: O(n) — each node has two pointers (prev and next)

Algorithm

Insertion at Beginning:
1. Allocate memory for new node.
2. Set its data.
3. Set next of new node to current head.
4. Set prev of head to new node (if head exists).
5. Update head to new node.
Insertion at End:
1. Allocate new node, set data.
2. Traverse to the last node.
3. Set next of last node to new node.
4. Set prev of new node to last node.

Insertion at Position (after a node with value x):


1. Traverse until node with data == x.
2. Set new node’s prev to current, and next to current’s next.
3. Update links of neighboring nodes accordingly.

Deletion at Beginning:
1. Set head to head’s next.
2. Free previous head node.
3. Set new head’s prev to NULL.

Deletion at End:
1. Traverse to last node.
2. Set second last node’s next to NULL.
3. Free last node.

Deletion at Position (value x):


1. Traverse to node with data == x.
2. Adjust prev and next pointers of neighboring nodes.
3. Free node.
Pseudocode
InsertAtBeginning(data):
newNode ← allocate node
newNode.data ← data
newNode.prev ← NULL
newNode.next ← head
If head ≠ NULL then
head.prev ← newNode
head ← newNode

InsertAtEnd(data):
newNode ← allocate node
newNode.data ← data
newNode.next ← NULL
If head == NULL then
newNode.prev ← NULL
head ← newNode
Else
temp ← head
While temp.next ≠ NULL
temp ← temp.next
temp.next ← newNode
newNode.prev ← temp

DeleteFromBeginning():
If head == NULL then
Print "List is empty"
Else
temp ← head
head ← head.next
If head ≠ NULL then
head.prev ← NULL
Free temp

Doubly Linked List Code :


#include <stdio.h>
#include <stdlib.h>

struct Node {
int data;
struct Node* prev;
struct Node* next;
};

struct Node* head = NULL;

void insertAtBeginning(int data) {


struct Node* newNode = (struct Node*) malloc(sizeof(struct Node));
newNode->data = data;
newNode->prev = NULL;
newNode->next = head;
if (head != NULL) {
head->prev = newNode;
}
head = newNode;
}

void insertAtEnd(int data) {


struct Node* newNode = (struct Node*) malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL;
if (head == NULL) {
newNode->prev = NULL;
head = newNode;
return;
}
struct Node* temp = head;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = newNode;
newNode->prev = temp;
}

void deleteFromBeginning() {
if (head == NULL) return;
struct Node* temp = head;
head = head->next;
if (head != NULL) {
head->prev = NULL;
}
free(temp);
}
void deleteFromEnd() {
if (head == NULL) return;
struct Node* temp = head;
if (temp->next == NULL) {
head = NULL;
free(temp);
return;
}
while (temp->next != NULL) {
temp = temp->next;
}
temp->prev->next = NULL;
free(temp);
}

void insertAfterValue(int value, int data) {


struct Node* temp = head;
while (temp != NULL && temp->data != value) {
temp = temp->next;
}
if (temp == NULL) return;
struct Node* newNode = (struct Node*) malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = temp->next;
newNode->prev = temp;
if (temp->next != NULL) {
temp->next->prev = newNode;
}
temp->next = newNode;
}

void deleteByValue(int value) {


struct Node* temp = head;
while (temp != NULL && temp->data != value) {
temp = temp->next;
}
if (temp == NULL) return;
if (temp->prev != NULL) {
temp->prev->next = temp->next;
} else {
head = temp->next;
}
if (temp->next != NULL) {
temp->next->prev = temp->prev;
}
free(temp);
}

void displayForward() {
struct Node* temp = head;
while (temp != NULL) {
printf("%d ", temp->data);
temp = temp->next;
}
printf("\n");
}

void displayBackward() {
struct Node* temp = head;
if (temp == NULL) return;
while (temp->next != NULL) {
temp = temp->next;
}
while (temp != NULL) {
printf("%d ", temp->data);
temp = temp->prev;
}
printf("\n");
}

int main() {
insertAtBeginning(10);
insertAtBeginning(20);
insertAtEnd(5);
insertAfterValue(10, 15);
displayForward(); // 20 10 15 5
displayBackward(); // 5 15 10 20
deleteByValue(10);
deleteFromEnd();
deleteFromBeginning();
displayForward(); // 15
return 0;
}
Circular Linked List:
A Circular Linked List (CLL) is a variation of a linked list where the last node points
back to the first node, forming a circle. It can be singly or doubly linked, but this
overview covers singly circular linked list.
In a singly circular linked list, each node contains: Data, A pointer to the next node,
The last node’s next pointer points to the head node instead of NULL.

Characteristics of Circular Linked List


Characteristic Description
Type Non-linear, dynamic data structure
Nodes Each node has data and next
Last Node Points To Head (first node)
Circular Nature Yes
Traversal Possible from any node
Dynamic Yes (can grow/shrink at runtime)
Head and Tail Head is typically maintained, tail points to head
Useful For Scheduling (e.g., round-robin), circular buffering

Time Complexities
Operation Time Complexity
Traversal O(n)
Insertion at Front O(n) (without tail), O(1) (with tail)
Insertion at End O(n) (without tail), O(1) (with tail)
Deletion at Front O(n) (without tail), O(1) (with tail)
Deletion at End O(n)
Deletion by Value O(n)
Search O(n)

Space Complexity: O(n)

Algorithm
Insertion at Beginning
1. Allocate node, set data.
2. If list is empty:
 Point node’s next to itself.
 Set head to node.
3. Else:
 Traverse to last node.
 Point new node’s next to head.
 Point last node’s next to new node.
 Set head to new node.

Insertion at End
1. Allocate node, set data.
2. If list is empty:
 Point node’s next to itself.
 Set head to node.
3. Else:
 Traverse to last node.
 Point last node’s next to new node.
 Point new node’s next to head.

Deletion at Beginning
1. If list empty, return.
2. If one node:
 Free node
 Set head to NULL.
3. Else:
 Traverse to last node.
 Set head to head->next.
 Set last->next to new head.
 Free old head.

Deletion at End
1. If list empty, return.
2. If one node:
 Free node
 Set head to NULL.
3. Else:
 Traverse to second last node.
 Free last node.
 Set second last’s next to head.

Traversal
Start from head and keep going to next until reaching head again.
Pseudocode
InsertAtBeginning(data):
newNode ← allocate
newNode.data ← data
If head == NULL then
newNode.next ← newNode
head ← newNode
Else
temp ← head
While temp.next ≠ head
temp ← temp.next
newNode.next ← head
temp.next ← newNode
head ← newNode

InsertAtEnd(data):
newNode ← allocate
newNode.data ← data
If head == NULL then
newNode.next ← newNode
head ← newNode
Else
temp ← head
While temp.next ≠ head
temp ← temp.next
temp.next ← newNode
newNode.next ← head

DeleteFromBeginning():
If head == NULL then return
If head.next == head then
Free head
head ← NULL
Else
temp ← head
While temp.next ≠ head
temp ← temp.next
temp.next ← head.next
Free head
head ← temp.next

Circular Linked List Code :


#include <stdio.h>
#include <stdlib.h>

struct Node {
int data;
struct Node* next;
};

struct Node* head = NULL;

void insertAtBeginning(int data) {


struct Node* newNode = (struct Node*) malloc(sizeof(struct Node));
newNode->data = data;
if (head == NULL) {
newNode->next = newNode;
head = newNode;
return;
}
struct Node* temp = head;
while (temp->next != head) {
temp = temp->next;
}
newNode->next = head;
temp->next = newNode;
head = newNode;
}

void insertAtEnd(int data) {


struct Node* newNode = (struct Node*) malloc(sizeof(struct Node));
newNode->data = data;
if (head == NULL) {
newNode->next = newNode;
head = newNode;
return;
}
struct Node* temp = head;
while (temp->next != head) {
temp = temp->next;
}
temp->next = newNode;
newNode->next = head;
}

void deleteFromBeginning() {
if (head == NULL) return;
if (head->next == head) {
free(head);
head = NULL;
return;
}
struct Node* temp = head;
struct Node* last = head;
while (last->next != head) {
last = last->next;
}
head = head->next;
last->next = head;
free(temp);
}

void deleteFromEnd() {
if (head == NULL) return;
if (head->next == head) {
free(head);
head = NULL;
return;
}
struct Node* temp = head;
struct Node* prev = NULL;
while (temp->next != head) {
prev = temp;
temp = temp->next;
}
prev->next = head;
free(temp);
}

void display() {
if (head == NULL) return;
struct Node* temp = head;
do {
printf("%d ", temp->data);
temp = temp->next;
} while (temp != head);
printf("\n");
}

int main() {
insertAtBeginning(30);
insertAtBeginning(20);
insertAtEnd(40);
insertAtEnd(50);
display(); // 20 30 40 50
deleteFromBeginning();
deleteFromEnd();
display(); // 30 40
return 0;
}
Doubly Circular Linked List:
A Doubly Circular Linked List (DCLL) is a type of linked list in which each node has
three parts: data, a pointer to the next node, and a pointer to the previous node.
The last node's next points to the head, and the head's prev points to the last node,
forming a closed loop in both directions.

Characteristics of Doubly Circular Linked List


Characteristic Description
Type Non-linear, dynamic data structure
Direction Bidirectional traversal
Last Node Points To Head (next) and Head (prev of last to head)
Head Node Points To Last node (via prev)
Circular Yes, both forward and backward
Useful For Playlists, navigation systems, schedulers, etc.
Memory Overhead Higher (due to two pointers per node)
Dynamic Yes

Time Complexities
Operation Time Complexity
Traversal (forward) O(n)
Traversal (reverse) O(n)
Insertion at Front O(1)
Insertion at End O(1)
Deletion at Front O(1)
Deletion at End O(1)
Deletion by Value O(n)
Search O(n)

Space Complexity: O(n)


Algorithm
Insertion at Beginning
1. Allocate node, set data.
2. If list is empty:
 Point new node's next and prev to itself.
 Set head to new node.
3. Else:
 Get tail (head->prev).
 Set new node's next to head, prev to tail.
 Adjust head->prev and tail->next to new node.
 Update head.

Insertion at End
1. Allocate a new node and assign it the given data.
2. If the list is empty:
 Set the node’s next and prev to itself.
 Make this node the head.
3. Else :
 Identify the last node (tail) using head->prev.
 Set the new node’s next to head.
 Set the new node’s prev to tail.
 Update tail->next to point to the new node.
 Update head->prev to point to the new node.
 The head remains unchanged.

Deletion at Beginning
1. If list empty, return.
2. If one node: Free and set head to NULL.
3. Else:
 Update head and pointers.
 Free old head.

Deletion at End
1. If the list is empty (head == NULL) : there is nothing to delete — exit.
2. If the list has only one node (head->next == head):
 Free the head node.
 Set head = NULL.
3. Else :
 Identify the last node (tail) using head->prev.
 Identify the second last node using tail->prev.
 Set second_last->next = head.Set head->prev = second_last.
 Free the tail node.
Pseudocode
InsertAtBeginning(data):
newNode ← allocate
newNode.data ← data
If head == NULL then
newNode.next ← newNode
newNode.prev ← newNode
head ← newNode
Else
tail ← head.prev
newNode.next ← head
newNode.prev ← tail
tail.next ← newNode
head.prev ← newNode
head ← newNode

InsertAtEnd(data):
newNode ← allocate
newNode.data ← data
If head == NULL then
newNode.next ← newNode
newNode.prev ← newNode
head ← newNode
Else
tail ← head.prev
newNode.next ← head
newNode.prev ← tail
tail.next ← newNode
head.prev ← newNode

DeleteFromBeginning():
If head == NULL then return
If head.next == head then
Free head
head ← NULL
Else
tail ← head.prev
temp ← head
head ← head.next
head.prev ← tail
tail.next ← head
Free temp
Doubly Circular Linked List :
#include <stdio.h>
#include <stdlib.h>

struct Node {
int data;
struct Node* next;
struct Node* prev;
};

struct Node* head = NULL;

void insertAtBeginning(int data) {


struct Node* newNode = (struct Node*) malloc(sizeof(struct Node));
newNode->data = data;
if (head == NULL) {
newNode->next = newNode;
newNode->prev = newNode;
head = newNode;
return;
}
struct Node* tail = head->prev;
newNode->next = head;
newNode->prev = tail;
head->prev = newNode;
tail->next = newNode;
head = newNode;
}

void insertAtEnd(int data) {


struct Node* newNode = (struct Node*) malloc(sizeof(struct Node));
newNode->data = data;
if (head == NULL) {
newNode->next = newNode;
newNode->prev = newNode;
head = newNode;
return;
}
struct Node* tail = head->prev;
newNode->next = head;
newNode->prev = tail;
tail->next = newNode;
head->prev = newNode;
}

void deleteFromBeginning() {
if (head == NULL) return;
if (head->next == head) {
free(head);
head = NULL;
return;
}
struct Node* tail = head->prev;
struct Node* temp = head;
head = head->next;
head->prev = tail;
tail->next = head;
free(temp);
}

void deleteFromEnd() {
if (head == NULL) return;
if (head->next == head) {
free(head);
head = NULL;
return;
}
struct Node* tail = head->prev;
struct Node* prev = tail->prev;
prev->next = head;
head->prev = prev;
free(tail);
}

void displayForward() {
if (head == NULL) return;
struct Node* temp = head;
do {
printf("%d ", temp->data);
temp = temp->next;
} while (temp != head);
printf("\n");
}

void displayBackward() {
if (head == NULL) return;
struct Node* tail = head->prev;
struct Node* temp = tail;
do {
printf("%d ", temp->data);
temp = temp->prev;
} while (temp != tail);
printf("\n");
}
int main() {
insertAtBeginning(30);
insertAtBeginning(20);
insertAtEnd(40);
insertAtEnd(50);
displayForward(); // 20 30 40 50
displayBackward(); // 50 40 30 20
deleteFromBeginning();
deleteFromEnd();
displayForward(); // 30 40
displayBackward(); // 40 30
return 0;
}

You might also like