Lecture 8 (Linked Lists)
Lecture 8 (Linked Lists)
Linked Lists
Computer Programming 2
2nd Semester 2024-2025
Topics
*Introduction to linked list
*Array versus linked list
*Linked lists in C
*Types of linked lists
* Single linked list
* Doubly linked list
* Circular linked list
* Operations on linked list
Linked List
• A linked list is a data structure which allows to store data
dynamically and manage data efficiently.
• Typically, a linked list, in its simplest form looks like the
following
header
A B C NULL
Linked List
• Few salient features
• There is a pointer (called header) that points to the first element (also called
node)
a 10 15 20 22 25 30
15
b f k b d
45
c
25 35 40 45 50
d
50
e
22 h
10 15 20 e 22 c 25 g 30 f
f a i
35
g
30
h 35 k 40 b 45 d 50
10
i
20 h
j 10 15 20 22 25 30
k
40
35 40 45 50
Array versus Linked Lists
• In Linked lists
• adjacency between any two elements are maintained by means of links
or pointers
struct node
node
{
int data; /* Data */ Data
struct node *next; /* pointer*/ next
} ;
Note:
Such structures which contain a member field pointing to the same structure type are
called self-referential structures.
Types of Lists: Single Linked List
Depending on the way in which the links are used to maintain
adjacency, several different types of linked lists are possible.
head
A B C NULL
Types of Lists: Double Linked List
Double linked list
• Pointers exist between adjacent nodes in both directions.
• The list can be traversed either forward or backward.
• Usually two pointers are maintained to keep track of the list, head and
tail.
head tail
A B C
Defining a Node of a Double Linked List
Each node of doubly linked list (DLL) consists of three fields:
• Item (or) Data
• Pointer of the next node in DLL
• Pointer of the previous node in DLL
node
Data
prev next
A B C
Circular Linked List
• A circular linked list is basically a linear linked list that may be single- or
double-linked.
• The only difference is that there is no any NULL value terminating the list.
• In fact in the list every node points to the next node and last node points to the
first node, thus forming a circle. Since it forms a circle with no end to stop it is
called as circular linked list.
• In circular linked list there can be no starting or ending node, whole node can be
traversed from any node.
• In order to traverse the circular linked list only once, we need to traverse entire
list until the starting node is not traversed again.
• A circular linked list can be implemented using both singly linked list and
doubly linked list.
head
A B C
Example 1: Creating a Single Linked List
Linked list to store and print roll number, name and age of 3 students.
#include <stdio.h>
struct stud
{
int roll;
char name[30];
int age;
struct stud *next;
};
main()
{
struct stud n1, n2, n3;
struct stud *p;
scanf (“%d %s %d”, &n1.roll, n1.name, &n1.age);
scanf (“%d %s %d”, &n2.roll,n2.name, &n2.age);
scanf (“%d %s %d”, &n3.roll,n3.name, &n3.age);
Example 1: Creating a Single Linked List
n1.next = &n2 ;
n2.next = &n3 ;
n3.next = NULL ;
/* Now traverse the list and print the elements */
p = &n1 ; /* point to 1st element */
while (p != NULL)
{
printf (“\n %d %s %d”, p->roll, p->name, p->age);
p = p->next;
}
}
Example 1: Illustration
The structure:
struct stud
{
int roll;
char name[30];
int age;
struct stud *next;
};
Also assume the list with three nodes n1, n2 and n3 for 3 students.
n1.next = &n2 ;
n2.next = &n3 ;
n3.next = NULL ; /* No more nodes follow */
roll
name
age
next NULL
n1 n2 n3
Dynamic Memory Allocation
Obtain and release memory during execution
malloc
– Takes number of bytes to allocate
- Use sizeof to determine the size of an object
– Returns pointer of type void *
- A void * pointer may be assigned to any pointer
- If no memory available, returns NULL
– Example
newPtr = malloc( sizeof( struct node ) );
free
– Deallocates memory allocated by malloc
– Takes a pointer as an argument
– free(newPtr);
Good Programming Practice
#include <stdio.h>
#include <stdlib.h>
struct node {
int data; //Data part
struct node *next; //Address part
}*header;
int main()
{
int n;
printf("Enter the total number of nodes: ");
scanf("%d", &n);
createList(n);
return 0;
}
Example 2: Creating a Single Linked List
void createList(int n)
{
struct node *newNode, *temp;
int data, i;
if(newNode == NULL)
{
printf("Unable to allocate memory.");
break;
}
else
{
printf("Enter the data of node %d: ", i);
scanf("%d", &data);
It creates a single node. For example, if the data entered is 100 then the list
look like
header
100 NULL
Creating a single linked list
If we need n number of nodes in the linked list:
• Allocate n newNodes, one by one.
• Read in the data for the newNodes.
• Modify the links of the newNodes so that the chain is formed.
It creates n number of nodes . For e.g. if the data entered is 200, 50, 30 then
the list look like
head
100 200 50 30 NULL
Example 3: Creating a Single Linked List
C-program to copy an array to a single linked list.
#include <stdio.h>
#include <stdlib.h>
struct node {
int data; //Data part
struct node *next; //Address part
};
int main()
{
struct node *header, *newNode, *temp;
int data, i, n, a[100];
printf("Enter the total number of data: ");
scanf("%d", &n);
// Write code here to initialize the array a with n elements //
...
Example 2: Creating a Single Linked List
/* A node is created by allocating memory to a structure */
newNode = (struct node *)malloc(sizeof(struct node));
if(newNode == NULL)
{
printf("Unable to allocate memory.");
break;
}
else
{
newNode->data = a[i]; //Links the data field of newNode with a[i]
newNode->next = NULL; //Links the address field of newNode with NULL
Once the linked list has been constructed and header points to the
first node of the list,
• Follow the pointers.
• Display the contents of the nodes as they are traversed.
• Stop when the next pointer points to NULL.
head
100 200 50 30 NULL
Insertion in a Linked List
Single Linked List: Insertion
Insertion steps:
• Create a new node
• Start from the header node
• Manage links to
• Insert at front
• Insert at end
• Insert at any position
Insertion at front
Step 3: Make the new node as the head node, i.e. now head node will point to newNode.
Insertion at front
/*Create a new node and insert at the beginning of the linked list.*/
if(newNode == NULL)
{
printf("Unable to allocate memory.");
}
else
{
newNode->data = data; //Links the data part
newNode->next = head; //Links the address part
Step 2: Traverse to the last node of the linked list and connect the last node of the list with the
new node, i.e. last node will now point to new node. (lastNode->next = newNode).
Insertion at End
/* Create a new node and insert at the end of the linked list. */
void insertNodeAtEnd(int data)
{
struct node *newNode, *temp;
newNode = (struct node*)malloc(sizeof(struct node));
if(newNode == NULL)
{
printf("Unable to allocate memory.");
}
else
{
newNode->data = data; //Links the data part
newNode->next = NULL;
temp = head;
Step 2: Traverse to the n-1th position of the linked list and connect the new node with the
n+1th node. (newNode->next = temp->next) where temp is the n-1th node.
Single Linked List: Insertion at any position
Step 3: Now at last connect the n-1th node with the new node i.e. the n-1th node will now
point to new node. (temp->next = newNode) where temp is the n-1th node.
Insertion at any Position
/* Create a new node and insert at middle of the linked list.*/
if(newNode == NULL)
{
printf("Unable to allocate memory.");
}
else
{
newNode->data = data; //Links the data part
newNode->next = NULL;
temp = head;
Insertion at any Position
for(i=2; i<=position-1; i++) /* Traverse to the n-1 position */
{
temp = temp->next;
if(temp == NULL)
break;
}
if(temp != NULL)
{
/* Links the address part of new node */
newNode->next = temp->next;
Step 2: Create a newNode that is to be inserted and assign some data to its data field.
Doubly Linked List: Insertion at any Position
Step 3: Connect the next address field of newNode with the node pointed by next address
field of temp node.
Step 4: Connect the previous address field of newNode with the temp node.
Doubly Linked List: Insertion at any Position
Step 5: Check if temp.next is not NULL then, connect the previous address field of node
pointed by temp.next to newNode.
int main()
{
int n, data;
head = NULL;
last = NULL;
last = head;
for(i=2; i<=n; i++){ /* Creates and links rest of the n-1 nodes */
newNode = (struct node *)malloc(sizeof(struct node));
printf("Enter data of %d node: ", i);
scanf("%d", &data);
newNode->data = data;
newNode->prev = last; //Links new node with the previous node
newNode->next = NULL;
newNode->data = data;
newNode->next = temp->next; //Connects new node with n+1th node
newNode->prev = temp; //Connects new node with n-1th node
if(temp->next != NULL)
{
temp->next->prev = newNode; /* Connects n+1th node with new node */
}
temp->next = newNode; /* Connects n-1th node with new node */
printf("NODE INSERTED SUCCESSFULLY AT %d POSITION\n", position);
}
else{
printf("Error, Invalid position\n");
}
}
}
Doubly Linked List: Insertion at any Position
void displayList()
{
struct node * temp;
int n = 1;
if(head == NULL)
{
printf("List is empty.\n");
}
else
{
temp = head;
printf("DATA IN THE LIST:\n");
while(temp != NULL)
{
printf("DATA of %d node = %d\n", n, temp->data);
n++;
Deletion steps
• Start from the header node
• Manage links to
• Delete at front
• Delete at end
• Delete at any position
• Freeing up the node as free space.
Free Memory after Deletion
• Do not forget to free() memory location dynamically allocated
for a node after deletion of that node.
Step 2: Move the head to the second node of the linked list (head = head->next).
Single linked list: Deletion at front
Step 3: Disconnect the connection of first node to second node.
if(head == NULL)
{
printf("List is already empty.");
}
else
{
toDelete = head;
head = head->next;
Step 2: If the last node is the head node then make the head node as NULL else disconnect
the second last node with the last node i.e. secondLastNode->next = NULL
Single linked list: Deletion at End
Step 3: Free the memory occupied by the last node.
Deletion at End
Step 2: Reconnect n-1th node with the n+1th node i.e. prevNode->next = toDelete->next
(Where prevNode is n-1th node and toDelete node is the nth node and toDelete->next is the n+1th
node).
Single Linked List: Deletion at any Position
Step 3: Free the memory occupied by the nth node i.e. toDelete node.
Deletion at any Position
/* Delete the node at any given position of the linked list */
void deleteMiddleNode(int position)
{
int i;
struct node *toDelete, *prevNode;
if(head == NULL)
{
printf("List is already empty.");
}
else
{
toDelete = head;
prevNode = head;
if(toDelete == NULL)
break;
}
Deletion at any Position
if(toDelete != NULL)
{
if(toDelete == head)
head = head->next;
prevNode->next = toDelete->next;
toDelete->next = NULL;
int main()
{
struct node *a, *b;
a = createList(5); // e.g: a: 5->4->3->2->1
b = createList(5); // e.g: b: 5->4->3->2->1
areIdentical(a, b)? printf("Identical"): printf("Not identical");
return 0;
}
Few Exercises to Try Out
Write a function to:
• Concatenate or merge two given list into one big list.
node *concatenate(node *a, node *b);
• Compare two given list with same data but different arrangement.
e.g: a: 5->4->3->2->1
b: 1->2->3->4->5
• Count the number of nodes in the given list using iterative method
and recursive method.
Ordering Linked List
Single Linked List: Reversing
Reversing a list can be performed in two ways:
• Iterative method
• Recursive method
Step 3: Move the head node to its next node i.e. head = head->next.
Reversing a List
Step 4: Now, re-connect the current node to its previous node
i.e. curNode->next = prevNode;
Step 5: Point the previous node to current node and current node to head node. Means they
should now point to prevNode = curNode; and curNode = head.
Reversing a List
Step 6: Repeat steps 3-5 till head pointer becomes NULL.
Step 7: Now, after all nodes has been re-connected in the reverse order. Make the last node
as the first node. Means the head pointer should point to prevNode pointer.
• Perform head = prevNode; And finally you end up with a reversed linked list of
its original.
Reversing a List: Iterative Method
void reverseList()
{
struct node *prevNode, *curNode;
if(head != NULL)
{
prevNode = head;
curNode = head->next;
head = head->next;
while(head != NULL)
{
head = head->next;
curNode->next = prevNode;
prevNode = curNode;
curNode = head;
}
int main()
{
int n = 10;
createList(n); // creates 10 nodes in the linked list
Recursive_Reverse(head);
return 0;
}
Single Linked List: Sorting
The linked list can be ordered using any of the following sorting
algorithms:
• Insertion sort
• Selection sort
• Merge sort
• Quick sort
• Bubble sort, etc.
// Traverse the given linked list and insert every node to be sorted
struct node *current = *head_ref;
while (current != NULL)
{
struct node *next = current->next;
struct node {
int data;
struct node * next;
}*head;
int main()
{
int n, data;
head = NULL;
return 0;
}
Circular Linked List: Creation of List
void createList(int n)
{
int i, data;
struct node *prevNode, *newNode;
if(n >= 1){ /* Creates and links the head node */
head = (struct node *)malloc(sizeof(struct node));
head->data = data;
head->next = NULL;
prevNode = head;
for(i=2; i<=n; i++){ /* Creates and links rest of the n-1 nodes */
newNode = (struct node *)malloc(sizeof(struct node));
newNode->data = data;
newNode->next = NULL;
prevNode->next = newNode; //Links the previous node with newly created node
prevNode = newNode; //Moves the previous node ahead
}
prevNode->next = head; //Links the last node with first node
printf("\nCIRCULAR LINKED LIST CREATED SUCCESSFULLY\n");
}
}
Circular Linked List: Traversal of List
void displayList()
{
struct node *current;
int n = 1;
if(head == NULL)
{
printf("List is empty.\n");
}
else
{
current = head;
printf("DATA IN THE LIST:\n");
do {
printf("Data %d = %d\n", n, current->data);
current = current->next;
n++;
}while(current != head);
}
}
Few Exercises to Try Out
For circular linked list write a function to:
• Insert a node at any position of the list and delete from the
beginning of the list.
insert_position(data,position);
delete_front();