Data Structure Module 3
Data Structure Module 3
Singly Linked List-Operations on Linked List. Doubly Linked List, Circular Linked List,
Stacks and Queues using Linked List, Polynomial representation using Linked List
Memory allocation and de-allocation-First-fit, Best-fit and Worst-fit allocation schemes
Array element access is random access In linked list , access is sequential and it
and it is fast is slow
Array need space to store only the data In linked list additional space is
element. No extra space is required required to store the pointers
For insertion & deletion, it takes more Insertion and deletion take less time.
time. For dictionary operation array But dictionary operation take very less
take less time time.
Where ‘next’ is a pointer to a struct node variable, it should be remembered that the
pointer to the structure is similar to the pointer to any other variable.
Linked List
When we want to work with an unknown number of data values, we use a linked list data
structure to organize that data. The linked list is a linear data structure that contains a
sequence of elements such that each element links to its next element in the sequence.
Each element in a linked list is called "Node".
Singly Linked List
Simply a list is a sequence of data, and the linked list is a sequence of data linked with
each other.
Singly linked list is a sequence of elements in which every element has link to its
next element in the sequence.
Every "Node" contains two fields, data field, and the next field. The data field is used to
store actual value of the node and next field is used to store the address of next node in
the sequence.
The graphical representation of a node in a singly linked list is as follows...
In a singly linked list, the address of the first node is always stored in a reference node
known as "front" (Some times it is also known as "head").
Always next part (reference part) of the last node must be NULL.
Operations on Singly Linked List
The following operations are performed on a Singly Linked List
● Insertion
● Deletion
● Display
Before we implement actual operations, first we need to set up an empty list. First,
perform the following steps before implementing actual operations.
● Step 1 - Include all the header files which are used in the program.
● Step 2 - Declare all the user defined functions.
● Step 3 - Define a Node structure with two members data and next
● Step 4 - Define a Node pointer 'head' and set it to NULL.
● Step 5 - Implement the main method by displaying operations menu and make
suitable function calls in the main method to perform user selected operation.
Insertion
In a singly linked list, the insertion operation can be performed in three ways. They are
as follows...
1. Inserting At Beginning of the list
2. Inserting At End of the list
3. Inserting At Specific location in the list
Inserting At Beginning of the list
We can use the following steps to insert a new node at beginning of the singly linked list...
● Step 1 - Create a newNode with given value.
● Step 2 - Check whether list is Empty (head == NULL)
● Step 3 - If it is Empty then, set newNode→next = NULL and head = newNode.
● Step 4 - If it is Not Empty then, set newNode→next = head and head = newNode.
Inserting At End of the list
We can use the following steps to insert a new node at end of the singly linked list...
● Step 1 - Create a newNode with given value and newNode → next as NULL.
● Step 2 - Check whether list is Empty (head == NULL).
● Step 3 - If it is Empty then, set head = newNode.
● Step 4 - If it is Not Empty then, define a node pointer temp and initialize
with head.
● Step 5 - Keep moving the temp to its next node until it reaches to the last node in
the list (until temp → next is equal to NULL).
● Step 6 - Set temp → next = newNode.
Inserting At Specific location in the list (After a Node)
We can use the following steps to insert a new node after a node in the singly linked list...
● Step 1 - Create a newNode with given value.
● Step 2 - Check whether list is Empty (head == NULL)
● Step 3 - If it is Empty then, set newNode → next = NULL and head = newNode.
● Step 4 - If it is Not Empty then, define a node pointer temp and initialize
with head.
● Step 5 - Keep moving the temp to its next node until it reaches to the node after
which we want to insert the newNode (until temp1 → data is equal to location,
here location is the node value after which we want to insert the newNode).
● Step 6 - Every time check whether temp is reached to last node or not. If it is
reached to last node then display 'Given node is not found in the list!!! Insertion
not possible!!!' and terminate the function. Otherwise move the temp to next
node.
● Step 7 - Finally, Set 'newNode → next = temp → next' and 'temp →
next = newNode'
Deletion
In a singly linked list, the deletion operation can be performed in three ways. They are as
follows...
1. Deleting from Beginning of the list
2. Deleting from End of the list
3. Deleting a Specific Node
Deleting from Beginning of the list
We can use the following steps to delete a node from the beginning of the singly linked
list...
● Step 1 - Check whether list is Empty (head == NULL)
● Step 2 - If it is Empty then, display 'List is Empty!!! Deletion is not possible' and
terminate the function.
● Step 3 - If it is Not Empty then, define a Node pointer 'temp' and initialize
with head.
● Step 4 - Check whether list is having only one node (temp → next == NULL)
● Step 5 - If it is TRUE then set head = NULL and delete temp (Setting Empty list
conditions)
● Step 6 - If it is FALSE then set head = temp → next, and delete temp.
Deleting from End of the list
We can use the following steps to delete a node from end of the singly linked list...
● Step 1 - Check whether list is Empty (head == NULL)
● Step 2 - If it is Empty then, display 'List is Empty!!! Deletion is not possible' and
terminate the function.
● Step 3 - If it is Not Empty then, define two Node pointers 'temp1' and 'temp2' and
initialize 'temp1' with head.
● Step 4 - Check whether list has only one Node (temp1 → next == NULL)
● Step 5 - If it is TRUE. Then, set head = NULL and delete temp1. And terminate the
function. (Setting Empty list condition)
● Step 6 - If it is FALSE. Then, set 'temp2 = temp1 ' and move temp1 to its next
node. Repeat the same until it reaches to the last node in the list. (until temp1 →
next == NULL)
● Step 7 - Finally, Set temp2 → next = NULL and delete temp1.
Deleting a Specific Node from the list
We can use the following steps to delete a specific node from the singly linked list...
● Step 1 - Check whether list is Empty (head == NULL)
● Step 2 - If it is Empty then, display 'List is Empty!!! Deletion is not possible' and
terminate the function.
● Step 3 - If it is Not Empty then, define two Node pointers 'temp1' and 'temp2'
and initialize 'temp1' with head.
● Step 4 - Keep moving the temp1 until it reaches to the exact node to be deleted or
to the last node. And every time set 'temp2 = temp1' before moving the 'temp1'
to its next node.
● Step 5 - If it is reached to the last node then display 'Given node not found in the
list! Deletion not possible!!!'. And terminate the function.
● Step 6 - If it is reached to the exact node which we want to delete, then check
whether list is having only one node or not
● Step 7 - If list has only one node and that is the node to be deleted, then
set head = NULL and delete temp1 (free(temp1)).
● Step 8 - If list contains multiple nodes, then check whether temp1 is the first node
in the list (temp1 == head).
● Step 9 - If temp1 is the first node then move the head to the next node (head =
head → next) and delete temp1.
● Step 10 - If temp1 is not first node then check whether it is last node in the list
(temp1 → next == NULL).
● Step 11 - If temp1 is last node then set temp2 → next = NULL and
delete temp1 (free(temp1)).
● Step 12 - If temp1 is not first node and not last node then set temp2 →
next = temp1 → next and delete temp1 (free(temp1)).
Displaying a Singly Linked List
We can use the following steps to display the elements of a singly linked list...
● Step 1 - Check whether list is Empty (head == NULL)
● Step 2 - If it is Empty then, display 'List is Empty!!!' and terminate the function.
● Step 3 - If it is Not Empty then, define a Node pointer 'temp' and initialize
with head.
● Step 4 - Keep displaying temp → data with an arrow (--->) until temp reaches to
the last node
● Step 5 - Finally display temp → data with arrow pointing to NULL (temp → data
---> NULL).
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
void insertAtBeginning(int);
void insertAtEnd(int);
void insertBetween(int,int);
void display();
void removeBeginning();
void removeEnd();
void removeSpecific(int);
struct Node
{
int data;
struct Node *next;
}*head = NULL;
void main()
{
int choice,value,loc1,loc2;
while(1)
{
printf("\n\n****** MENU ******\n1. Insert At Beginning\n2. Insert At
End\n3. Insert Between\n 4. Delete from Beginning\n5. Delete At End\n6.
Delete specific \n7. Display \n8. Exit\nEnter your choice: ");
scanf("%d",&choice);
switch(choice)
{
case 1: printf("Enter value to be inserted");
scanf("%d",&value);
insertAtBeginning(value);
break;
case 3: printf("Enter the value and where you want to insert: ");
scanf("%d%d",&value,&loc1);
insertBetween(value,loc1);
break;
case 4: removeBeginning();
break;
case 5: removeEnd();
break;
if(head->next == NULL)
head = NULL;
else
{
while(temp1->next != NULL)
{
temp2 = temp1;
temp1 = temp1->next;
}
temp2->next = NULL;
}
free(temp1);
printf("\nOne node deleted!!!\n\n");
}
}
void removeSpecific(int delValue)
{
struct Node *temp1 = head, *temp2;
while(temp1->data != delValue)
{
if(temp1 -> next == NULL)
{
printf("\nGiven node not found in the list!!!");
}
temp2 = temp1;
temp1 = temp1 -> next;
}
temp2 -> next = temp1 -> next;
free(temp1);
printf("\nOne node deleted!!!\n\n");
}
void display()
{
if(head == NULL)
{
printf("\nList is Empty\n");
}
else
{
struct Node *temp = head;
printf("\n\nList elements are - \n");
while(temp->next != NULL)
{
printf("%d --->",temp->data);
temp = temp->next;
}
printf("%d --->NULL",temp->data);
}
}
Operations
In a circular linked list, we perform the following operations...
1. Insertion
2. Deletion
3. Display
Before we implement actual operations, first we need to setup empty list. First perform
the following steps before implementing actual operations.
● Step 1 - Include all the header files which are used in the program.
● Step 2 - Declare all the user defined functions.
● Step 3 - Define a Node structure with two members data and next
● Step 4 - Define a Node pointer 'head' and set it to NULL.
● Step 5 - Implement the main method by displaying operations menu and make
suitable function calls in the main method to perform user selected operation.
Insertion
In a circular linked list, the insertion operation can be performed in three ways. They are
as follows...
1. Inserting At Beginning of the list
2. Inserting At End of the list
3. Inserting At Specific location in the list
Inserting At Beginning of the list
We can use the following steps to insert a new node at beginning of the circular linked
list...
● Step 1 - Create a newNode with given value.
● Step 2 - Check whether list is Empty (head == NULL)
● Step 3 - If it is Empty then, set head = newNode and newNode→next = head .
● Step 4 - If it is Not Empty then, define a Node pointer 'temp' and initialize with
'head'.
● Step 5 - Keep moving the 'temp' to its next node until it reaches to the last node
(until 'temp → next == head').
● Step 6 - Set 'newNode → next =head', 'head = newNode' and 'temp →
next = head'.
Inserting At End of the list
We can use the following steps to insert a new node at end of the circular linked list...
● Step 1 - Create a newNode with given value.
● Step 2 - Check whether list is Empty (head == NULL).
● Step 3 - If it is Empty then, set head = newNode and newNode → next = head.
● Step 4 - If it is Not Empty then, define a node pointer temp and initialize
with head.
● Step 5 - Keep moving the temp to its next node until it reaches to the last node in
the list (until temp → next == head).
● Step 6 - Set temp → next = newNode and newNode → next = head.
#include<stdio.h>
#include<stdlib.h>
void insertAtBeginning(int);
void insertAtEnd(int);
void insertAfter(int,int);
void deleteBeginning();
void deleteEnd();
void deleteSpecific(int);
void display();
struct Node
{
int data;
struct Node *next;
} *head = NULL;
void main()
{
int choice,value, location;
while(1)
{
printf("\n\n****** MENU ******\n 1. Insert At Beginning\n2. Insert At End\n3. Insert
Between\n 4. Delete from Beginning\n5. Delete At End\n6. Delete specific \n7. Display
\n8. Exit\nEnter your choice: ");
scanf("%d",&choice);
switch(choice)
{
case 1: printf("Enter value to be inserted");
scanf("%d",&value);
insertAtBeginning(value);
break;
case 3: printf("Enter the value and location after which you want to insert: ");
scanf("%d%d",&value,&location);
insertAfter(value,location);
break;
case 4: deleteBeginning();
break;
case 5: deleteEnd();
break;
case 7: display();
break;
case 8: exit(0);
void deleteBeginning()
{
if(head == NULL)
printf("List is Empty!!! Deletion not possible!!!");
else
{
struct Node *temp1, *temp2;
temp1=temp2= head;
if(temp1 -> next == head)
{
head = NULL;
free(temp1);
}
else
{ while(temp1->next!=head)
temp1 = temp1->next;
head = temp2 -> next;
temp1->next = head;
free(temp2);
}
printf("\nDeletion success!!!");
}
}
void deleteEnd()
{
if(head == NULL)
printf("List is Empty!!! Deletion not possible!!!");
else
{
struct Node *temp1 = head;
struct Node *temp2;
if(temp1 -> next == head)
{
head = NULL;
free(temp1);
}
else
{
while(temp1 -> next != head)
{
temp2 = temp1;
temp1 = temp1 -> next;
}
temp2 -> next = head;
free(temp1);
}
printf("\nDeletion success!!!");
}
}
void deleteSpecific(int delValue)
{
if(head == NULL)
printf("List is Empty!!! Deletion not possible!!!");
else
{
struct Node *temp1 = head;
struct Node *temp2;
while(temp1 -> data != delValue)
{
if(temp1 -> next == head)
{
printf("\nGiven node is not found in the list!!!");
}
else
{
temp2 = temp1;
temp1 = temp1 -> next;
}
}
Here, 'link1' field is used to store the address of the previous node in the
sequence, 'link2' field is used to store the address of the next node in the sequence
and 'data' field is used to store the actual value of that node.
Example
}
void pop()
{
if(top == NULL)
printf("\nStack is Empty!!!\n");
else
{
struct Node *temp = top;
printf("\nDeleted element: %d", temp->data);
top = temp->next;
free(temp);
}
}
void display()
{
if(top == NULL)
printf("\nStack is Empty!!!\n");
else
{
struct Node *temp = top;
while(temp->next != NULL)
{
printf("%d--->",temp->data);
temp = temp -> next;
}
printf("%d--->NULL",temp->data);
}
}
struct Node
{
int data;
struct Node *next;
}*front = NULL,*rear = NULL;
void insert(int);
void delete();
void display();
void main()
{
int choice, value;
printf("\n:: Queue Implementation using Linked List ::\n");
while(1)
{
printf("\n****** MENU ******\n");
printf("1. Insert\n2. Delete\n3. Display\n4. Exit\n");
printf("Enter your choice: ");
scanf("%d",&choice);
switch(choice)
{
case 1: printf("Enter the value to be insert: ");
scanf("%d", &value);
insert(value);
break;
case 2: delete(); break;
case 3: display(); break;
case 4: exit(0);
default: printf("\nWrong selection!!! Please try again!!!\n");
}
}
}
void insert(int value)
{
struct Node *newNode;
newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = value;
newNode -> next = NULL;
if(front == NULL)
front = rear = newNode;
else
{
rear -> next = newNode;
rear = newNode;
}
printf("\nInsertion is Success!!!\n");
}
void delete()
{
if(front == NULL)
printf("\nQueue is Empty!!!\n");
else
{
struct Node *temp = front;
front = front -> next;
printf("\nDeleted element: %d\n", temp->data);
free(temp);
}
}
void display()
{
if(front == NULL)
printf("\nQueue is Empty!!!\n");
else
{
struct Node *temp = front;
while(temp->next != NULL)
{
printf("%d--->",temp->data);
temp = temp -> next;
}
printf("%d--->NULL\n",temp->data);
}
}
To store a polynomial as a Linked List , we have a struct node like below. The data part of
the linked list node holds coefficient and exponent of polynomial terms. The link field
points to the next term of polynomial.
A list of Nodes are used to represent a polynomial.The coefficients and exponent of the
polynomial of a term are stored in a node. Each term of polynomial is linked and the end
of polynomial is identified by the link field with value “NULL”
struct Node
{
int coeff;
int exp;
struct Node *next;
}
Let us consider an example to represent a polynomial using linked list as follows:
Polynomial: 3x3-4x2+2x-9
Linked List:
In the above linked list, the external pointer ‘ROOT’ point to the first node of the linked
list. The first node of the linked list contains the information about the variable with the
highest degree. The first node points to the next node with next lowest degree of the
variable.
Representation of a polynomial using the linked list is beneficial when the operations on
the polynomial like addition and subtractions are performed. The resulting polynomial
can also be traversed very easily to display the polynomial.
#include<stdio.h>
#include<stdlib.h>
struct node
{
int coeft;
int degree;
struct node *link;
};
typedef struct node poly;
main()
{
poly *root,*temp,*new;
int hdegree, coeft;
root=NULL;
Addition of Polynomials
● Step 1 - Include all the header files which are used in the program. And declare
all the user defined functions.
● Step 2 - Define a 'Node' structure with three members and pow, coeff and next.
● Step 3 – Define three Node pointers 'poly1', ‘poly2’ and 'poly3' and set it
to NULL.
● Step 4 - Implement the main method and make suitable function calls in
the main method to perform creation and addition operation.
Addition
Step 1: Create list of polynomial1 and polynomial 2 using poly1 and poly2
Step 2: Loop around all values of linked list and dynamically create a newnode in
resultant polynomial whenever needed. Follow the steps below for addition.
Step 3 : If power of 1st polynomial is greater than 2nd, then store 1st as it is and
move its pointer.
poly->pow = poly1->pow;
poly->coeff = poly1->coeff;
poly1 = poly1->next;
Step 4: Otherwise , If power of 2nd polynomial is greater than 1st, then store 2nd
as it is and move its pointer.
poly->pow = poly2->pow;
poly->coeff = poly2->coeff;
poly2 = poly2->next;
Step 5: Otherwise If power of both polynomial numbers is same, then add their
coefficients and save it to resultant.
poly->pow = poly1->pow;
poly->coeff = poly1->coeff + poly2->coeff;
poly1 = poly1->next;
poly2 = poly2->next;
Polynomial Multiplication
● Step 2 - Define a 'Node' structure with three members and pow, coeff and next.
● Step 3 – Define three Node pointers 'poly1', ‘poly2’ and 'poly3' and set it
to NULL.
● Step 4 - Implement the main method and make suitable function calls in
the main method to perform creation and multiplication operation.
Multiplication
Step 1: Create list of polynomial1 and polynomial 2 using poly1 and poly2 using addnode
function
Step 2: Create two pointers and store the address of 1st and 2nd polynomials
Step 3: Loop until pointers of poly1 and poly2 becomes NULL-
Step 4: Multiply the coefficient of every term in poly1 with every term in poly2 and store
it in coeff. coeff = ptr1->coeff * ptr2->coeff;
Step 5:Add the power of every term in poly1 with every term in poly2 and store it in
power power = ptr1->power + ptr2->power;
Step 6: Every time create a newnode using addnode function with current coeff and
power to the resultant polynomial poly3.
Step 7 : When step 3 fails, Call function to add coefficients of polynomial terms having
same power.i.e to remve duplicates.
Step 7a: Pick terms one by one from resultant and compare the picked element with rest
of the elements
Step 7b: If power of two terms are same ptr1->power == ptr2->next->power .Add their
coefficients and put it in 1st element and remove the 2nd element
ptr1->coeff = ptr1->coeff + ptr2->next->coeff;
Step 8: Display resultant polynomial
Memory Allocations in Data Structures
Memory allocation is the process of setting aside sections of memory in a program to be
used to store variables, and instances of structures and classes.
There are two types of memory allocations possible in C:
1. Compile-time or Static allocation.
2. Run-time or Dynamic allocation (using pointers).
When the first statement is encountered, the compiler will allocate two bytes to each
variables x and y. The second statement results into the allocation of 20 bytes to the array
a (5*4, where there are five elements and each element of float type takes four bytes).
Stack space is used in Static Memory Heap space is used in Dynamic Memory
Allocation. Allocation.
It doesn't provide reusability of memory, It provides reusability of memory, while
while the program is running. So, it is less the program is running. So, it is more
efficient. efficient.
There are further four components in which our system's memory is divided:
Stack Segment (Static Memory)
Global Variables Segment (Static Memory)
Instructions / Text Segment (Static Memory)
Heap Segment (Dynamic Memory)
Dynamic Memory Allocation is a process in which we allocate or deallocate a block of
memory during the run-time of a program.
Dynamic Memory Allocation is considered as a very important concept in the field of Data
Structures and is used in almost every Data Structures like Linked Lists, Stacks, Dynamic
Arrays, Queue, etc.
Dynamic Memory Allocation
In C programming language, when we declare variables memory is allocated in space
called stack. The memory allocated in the stack is fixed at the time of compilation and
remains until the end of the program execution. When we create an array, we must
specify the size at the time of the declaration itself and it cannot be changed during the
program execution. This is a major problem when we do not know the number of values
to be stored in an array. To solve this we use the concept of Dynamic Memory Allocation.
The dynamic memory allocation allocates memory from heap storage. Dynamic memory
allocation is defined as follow...
Allocation of memory during the program execution is called dynamic memory
allocation.
or
Dynamic memory allocation is the process
of allocating the memory manually at the
time of program execution.
We use pre-defined or standard library
functions to allocate memory dynamically.
There are FOUR standard library functions
that are defined in the header file known
as "stdlib.h". They are as follows...
1. malloc()
2. calloc()
3. realloc()
4. free()
malloc()
malloc() is the standard library function used to allocate a memory block of specified
number of bytes and returns void pointer. The void pointer can be casted to any datatype.
If malloc() function unable to allocate memory due to any reason it returns NULL pointer.
Syntax
void* malloc(size_in_bytes)
calloc()
calloc() is the standard library function used to allocate multiple memory blocks of the
specified number of bytes and initializes them to ZERO. calloc() function returns void
pointer. If calloc() function unable to allocate memory due to any reason it returns a NULL
pointer. Generally, calloc() is used to allocate memory for array and structure. calloc()
function takes two arguments and they are 1. The number of blocks to be allocated, 2. Size
of each block in bytes
Syntax
void* calloc(number_of_blocks, size_of_each_block_in_bytes)
realloc()
realloc() is the standard library function used to modify the size of memory blocks that
were previously allocated using malloc() or calloc(). realloc() function returns void
pointer. If calloc() function unable to allocate memory due to any reason it returns NULL
pointer.
Syntax
void* realloc(*pointer, new_size_of_each_block_in_bytes)
free()
free() is the standard library function used to deallocate memory block that was
previously allocated using malloc() or calloc(). free() function returns void pointer. When
free() function is used with memory allocated that was created using calloc(), all the
blocks are get deallocated.
Syntax
void free(*pointer)
FIRST FIT - In the first fit , the approach is to allocate the first free partition or hole large
enough which can accommodate the process. It finishes after finding the first suitable free
partition.
BEST FIT - The best fit deals with allocating the smallest free partition which meets the
requirement of the requesting process. This algorithm first searches the entire list of free
partitions and considers the smallest hole that is adequate. It then tries to find a hole
which is close to actual process size needed.
WORST FIT - In worst fit approach is to locate largest available free portion so that the
portion left will be big enough to be useful. It is the reverse of best fit.
MEMORY ALLOCATION ALGORITHMS:
1. First Fit : In the first fit approach is to allocate the first free partition or hole large
enough which can accommodate the process. It finishes after finding the first suitable free
partition.
Advantage :Fastest algorithm because it searches as little as possible.
Disadvantage :The remaining unused memory areas left after allocation become waste if
it is too smaller. Thus request for larger memory requirement cannot be accomplished.
2. Best Fit: The best fit deals with allocating the smallest free partition which meets the
requirement of the requesting process. This algorithm first searches the entire list of free
partitions and considers the smallest hole that is adequate. It then tries to find a hole
which is close to actual process size needed.
Advantage Memory utilization is much better than first fit as it searches the smallest free
partition first available.
Disadvantage It is slower and may even tend to fill up memory with tiny useless holes.
3. Worst fit: In worst fit approach is to locate largest available free portion so that the
portion left will be big enough to be useful. It is the reverse of best fit.
Advantage: Reduces the rate of production of small gaps.
Disadvantage If a process requiring larger memory arrives at a later stage then it cannot
be accommodated as the largest hole is already split and occupied.
PROBLEM: Given five memory partitions of 100Kb, 500Kb, 200Kb, 300Kb, 600Kb (in
order), how would the first-fit, best-fit, and worstfit algorithms place processes of 212
Kb, 417 Kb, 112 Kb, and 426 Kb (in order)?
Which algorithm makes the most efficient use of memory?
ANSWER:
100 500 200 300 600
B1 B2 B3 B4 B5
First-fit:
212K is put in 500K partition
B1 B2 B3 B4 B5
Worst-fit:
B1 B2 B3 B4 B5