Data Structures r23 Full Material
Data Structures r23 Full Material
UNIT- 1
INTRODUCTION
A data structure is a particular way of storing and organizing data in a computer so that it can be
used efficiently.
Some common examples of data structures are arrays, linked lists, queues, stacks, binary trees,
and hash tables
Today computer programmers do not write programs just to solve a problem but to write an
efficient program.
When selecting a data structure to solve a problem, the following steps must be performed.
Analysis of the problem to determine the basic operations that must be supported.
Quantify the resource constraints for each operation.
Select the data structure that best meets these requirements.
The term data means a value or set of values. It specifies either the value of a variable or a constant
(e.g., marks of students, name of an employee, address of a customer, value of pi, etc.).
A record is a collection of data items. For example, the name, address, course, and marks obtained
are individual data items. But all these data items can be grouped together to form a record.
A file is a collection of related records. For example, if there are 60 students in a class, then there
are 60 records of the students. All these related records are stored in a file.
Data structures are generally categorized into two classes: primitive and non-primitive data
structures.
1
Primitive and Non-primitive Data Structures:
Primitive data structures are the fundamental data types which are supported by a
programming language. Some basic data types are integer, real, character, and boolean. The terms ‘data
type, basic data type’, and ‘primitivedata type’ are often used interchangeably.
. Non-primitive data structures are those data structures which are created using primitive datastructures.
Examples of such data structures include linked lists, stacks, trees, and graphs.
Non-primitive data structures can further be classified into two categories: linear and non-linear
data structures.
If the elements of a data structure are not stored in a sequential order, then it is a non-linear data
structure.
o The relationship of adjacency is not maintained between elements of a non-linear data
structure. Examples include trees and graphs.
Arrays:
An array is a collection of similar data elements. These data elements have the same data type.
The elements of the array are stored in consecutive memory locations and are referenced by an
index (also known as the subscript).
In C, arrays are declared using the following syntax: datatype name[size];
Ex: int marks[10];
limitations:
o Arrays are of fixed size.
o Data elements are stored in contiguous memory locations which may not be always available.
o Insertion and deletion of elements can be problematic because of shifting of elements from their
positions.
2
Linked Lists:
linked list is a dynamic data structure in which elements (called nodes) form a sequential list.
In a linked list, each node is allocated space as it is added to the list. Every node in the list points
to the next node in the list.
Every node contains the following
The value of the node or any other data that corresponds to that node
A pointer or link to the next node in the list
The first node in the list is pointed by Head/Start/First. The last node in the list contains a NULL
pointer to indicate that it is the end or tail of the list.
Advantage: Easier to insert or delete data elements
Disadvantage: Slow search operation and requires more memory space
Stacks:
A stack is a linear data structure in which insertion and deletion of elements are done at only one
end, which is known as the top of the stack.
Stack is called a last-in, first-out (LIFO)
structure because the last element which is
added to the stack is the first element which
is deleted from the stack.
Stacks can be implemented using arrays or
linked lists.
Every stack has a variable top associated
with it. Top is used to store the address of
the topmost element of the stack.
It is this position fromwhere the element will be added or deleted. There is another variable MAX,
which is used to store the maximum number of elements that the stack can store.
If top = NULL, then it indicates that the stack is empty and if top = MAX–1, then the stack is full.
A stack supports three basic operations: push, pop, and peep. The push operation adds an element
to the top of the stack. The pop operation removes the element from the top of the stack. And the
peep operation returns the value of the topmost element of the stack (without deleting it).
3
Queues:
A Queue is a linear data structure in which insertion can be done at rear end and deletion of
elements can be dome at front end.
A queue is a first-in, first-out (FIFO) data
structure in which the element that is
inserted first is the first one to be taken out.
Like stacks, queues can be implemented by using either arrays or linked lists.
A queue is full when rear = MAX – 1, An underflow condition occurs when we try to delete an
element from a queue that is already empty. If front = NULL and rear = NULL, then there is no
element in the queue.
Trees:
A tree is a non-linear data structure which consists of a collection of nodes arranged in a
hierarchical order.
One of the nodes is designated as the root node, and the remaining nodes can be partitioned into
disjoint sets such that each set is a sub-tree of the root
The simplest form of a tree is a binary tree. A binary tree
consists of a root node and left and right sub-trees, where both
sub-trees are also binary trees.
Each node contains a data element, a left pointer which points
to the left sub-tree, and a right pointer which points to the right
sub-tree.
The root element is the topmost node which is pointed by a
‘root’ pointer. If root = NULL then the tree is empty.
4
Here R is the root node and T1 and T2 are the left and right subtrees of R. If T1 is non-empty,
then T1 is said to be the left successor of R. Likewise, if T2 is non-empty, then it is called the
right successor of R.
Advantage: Provides quick search, insert, and delete operations
Disadvantage: Complicated deletion algorithm
Graphs:
A graph is a non-linear data structure which is a collection of vertices (also called nodes) and
edges that connect these vertices.
A node in the graph may represent a city and the edges
connectingthe nodes can represent roads.
A graph can also be used to represent a computer network
where the nodes are workstations and the edges are the network
connections.
Graphs do not have any root node. Rather, every node in the graph can be connected with
every another node in the graph.
Advantage: Best models real-world situations
Disadvantage: Some algorithms are slow and very complex
This section discusses the different operations that can be performed on the various data
structurespreviously mentioned.
Traversing It means to access each data item exactly once so that it can be processed. For
example, to print the names of all the students in a class.
Searching It is used to find the location of one or more data items that satisfy the given
constraint. Such a data item may or may not be present in the given collection of data items.
For example, to find the names of all the students who secured 100 marks in mathematics.
Inserting It is used to add new data items to the given list of data items. For example, to add
the details of a new student who has recently joined the course.
Deleting It means to remove (delete) a particular data item from the given collection of data
items. For example, to delete the name of a student who has left the course.
Sorting Data items can be arranged in some order like ascending order or descending order
depending on the type of application. For example, arranging the names of students in a class
in an alphabetical order, or calculating the top three winners by arranging the participants’
scores indescending order and then extracting the top three.
Merging Lists of two sorted data items can be combined to form a single list of sorted data items.
5
ABSTRACT DATA TYPE:
ADTs are like user defined data types which defines operations on values using functions without
specifying what is there inside the function and how the operations are performed.
Here we will learn about ADT but before understanding what ADT is let us consider different in-built
data types that are provided to us. Data types such as int, float, double, long, etc. are considered to be
in-built data types and we can perform basic operations with them such as addition, subtraction,
division, multiplication, etc. Now there might be a situation when we need operations for our user-defined
data type which have to be defined. These operations can be defined only as and when we require them.
So, in order to simplify the process of solving problems, we can create data structures along with their
operations, and such data structures that are not in-built are known as Abstract Data Type (ADT).
Abstract Data type (ADT) is a type (or class) for objects whose behaviour is defined by a set of values and
a set of operations. The definition of ADT only mentions what operations are to be performed but not
how these operations will be implemented. It does not specify how data will be organized in memory
and what algorithms will be used for implementing the operations. It is called “abstract” because it gives
an implementation-independent view.
The process of providing only the essentials and hiding the details is known as abstraction.
The user of data type does not need to know how that data type is implemented, for example, we have
been using Primitive values like int, float, char data types only with the knowledge that these data type
can operate and be performed on without any idea of how they are implemented.
6
Why ADT?
The program which used data structure is called a client program
It has access to the ADT i., e interface.
The program which implements the data structure is known as the implementation.
Advantages:
Let say, if someone wants to use the stack in the program, then he can simply use push and pop
operations without knowing its implementation.
Also, if in future, the implementation of stack is changed from array to linked list, then the client
program will work in the same way without being affected.
So, a user only needs to know what a data type can do, but not how it will be implemented. Think of ADT
as a black box which hides the inner structure and design of the data type. Now we’ll define three ADTs
namely List ADT, Stack ADT, Queue ADT.
1. List ADT
The data is generally stored in key sequence in a list which has a head structure consisting of
count, pointers and address of compare function needed to compare the data in the list.
The data node contains the pointer to a data structure and a self-referential pointer which points to
the next node in the list.
The List ADT Functions is given below:
get() – Return an element from the list at any given position.
insert() – Insert an element at any position of the list.
7
remove() – Remove the first occurrence of any element from a non-empty list.
removeAt() – Remove the element at a specified location from a non-empty list.
replace() – Replace an element at any position by another element.
size() – Return the number of elements in the list.
2. Stack ADT
In Stack ADT Implementation instead of data being stored in each node, the pointer to data is stored.
The program allocates memory for the data and address is passed to the stack ADT.
The head node and the data nodes are encapsulated in the ADT. The calling function can only see
the pointer to the stack.
The stack head structure also contains a pointer to top and count of number of entries currently in
stack.
push() – Insert an element at one end of the stack called top.
pop() – Remove and return the element at the top of the stack, if it is not empty.
peek() – Return the element at the top of the stack without removing it, if the stack is not empty.
size() – Return the number of elements in the stack.
isEmpty() – Return true if the stack is empty, otherwise return false.
isFull() – Return true if the stack is full, otherwise return false.
8
3. Queue ADT
The queue abstract data type (ADT) follows the basic design of the stack abstract data type.
Each node contains a void pointer to the data and the link pointer to the next element in the queue.
The program’s responsibility is to allocate memory for storing the data.
enqueue() – Insert an element at the end of the queue.
dequeue() – Remove and return the first element of the queue, if the queue is not empty.
peek() – Return the element of the queue without removing it, if the queue is not empty.
size() – Return the number of elements in the queue.
isEmpty() – Return true if the queue is empty, otherwise return false.
isFull() – Return true if the queue is full, otherwise return false.
Features of ADT:
Abstract data types (ADTs) are a way of encapsulating data and operations on that data into a single unit.
Some of the key features of ADTs include:
Abstraction: The user does not need to know the implementation of the data structure only essentials
are provided.
Better Conceptualization: ADT gives us a better conceptualization of the real world.
Robust: The program is robust and has the ability to catch errors.
Encapsulation: ADTs hide the internal details of the data and provide a public interface for users
to interact with the data. This allows for easier maintenance and modification of the data structure.
Data Abstraction: ADTs provide a level of abstraction from the implementation details of the data.
Users only need to know the operations that can be performed on the data, not how those operations
are implemented.
Data Structure Independence: ADTs can be implemented using different data structures, such as
arrays or linked lists, without affecting the functionality of the ADT.
Information Hiding: ADTs can protect the integrity of the data by allowing access only to
authorized users and operations. This helps prevent errors and misuse of the data.
Modularity: ADTs can be combined with other ADTs to form larger, more complex data structures.
This allows for greater flexibility and modularity in programming.
Overall, ADTs provide a powerful tool for organizing and manipulating data in a structured and efficient
manner.
Abstract data types (ADTs) have several advantages and disadvantages that should be considered when
deciding to use them in software development. Here are some of the main advantages and disadvantages of
using ADTs:
9
Advantages:
Encapsulation: ADTs provide a way to encapsulate data and operations into a single unit, making it
easier to manage and modify the data structure.
Abstraction: ADTs allow users to work with data structures without having to know the
implementation details, which can simplify programming and reduce errors.
Data Structure Independence: ADTs can be implemented using different data structures, which can
make it easier to adapt to changing needs and requirements.
Information Hiding: ADTs can protect the integrity of data by controlling access and preventing
unauthorized modifications.
Modularity: ADTs can be combined with other ADTs to form more complex data structures, which
can increase flexibility and modularity in programming.
Disadvantages:
Overhead: Implementing ADTs can add overhead in terms of memory and processing, which can
affect performance.
Complexity: ADTs can be complex to implement, especially for large and complex data structures.
Learning Curve: Using ADTs requires knowledge of their implementation and usage, which can
take time and effort to learn.
Limited Flexibility: Some ADTs may be limited in their functionality or may not be suitable for all
types of data structures.
Cost: Implementing ADTs may require additional resources and investment, which can increase the
cost of development.
PRELIMINARIES OF ALGORITHM:
10
Structure of an Algorithm:
1. Algorithm is a procedure consisting of heading and body. In body part we are writing
statements and in the head part we are writing the following.
Syntax: Algorithm name_of_Algo (param1,param2, …);
2. The beginning and ending of block should be indicated by ‘{‘ and ‘}’ or ‘start’ and ‘end’
respectively.
3. Every statement in the algorithm should be end with semicolon (;).
4. Single line
comments are
written using ‘//’
as beginning of
comments.
5. The identifier
should begin
with character
and it may be
combination of
alpha numeric.
6. Assignment operator (:=) we can use as follows
Variable := expression (or) value;
7. There are other type of operators such as Boolean operators (TRUE/FALSE), logical operators
(AND,OR,NOT) and relational operators (<,>,<=,>=,…..)
8. The input and output we can write it as read and print respectively.
9. The Array index are stored with in [ ] brackets. The index of array starts from ‘0’ to ‘N-1’.
Syntax: datatype Aray_name[size];
10. The conditional statements such as if-then (or) if-then-else are written as follows.
if(condition) then statements;
if(condition) then
statements;
else
statements;
11
TIME AND SPACE COMPLEXITY:
12
2. Space Complexity:
Space Complexity can be defined as amount of memory (or) space required by an Algorithm to
run.
To compute the space complexity we use 2 factors i. Constant ii. Instance characteristics.
The space requirement S(p) can be given as S(p) = C+Sp
Where C- Constant, it denotes the space taken for input and output.
Sp – Amount of space taken by an instruction, variable and identifiers.
13
SEARCHING:
LINEAR SEARCH:
Linear search is a technique which traverse the array sequentially to locate given item or search
element.
In Linear search, we access each element of an array one by one sequentially and see whetherr it
is desired element or not. We traverse the entire list and match each element of the list with the
item whose location is to be found. If the match found then location of the item is returned
otherwise the algorithm return NULL.
A search is successful then it will return the location of desired element
If A search will unsuccessful if all the elements are accessed and desired element not found.
Linear search is mostly used to search an unordered list in which the items are not sorted.
Step 6 - If last element in the list also doesn't match, then display "Element is not found!!!" and terminate
the function
Linear Search ( Array Arr, Value a ) // Arr is the name of the array, and a is the searched element.
Step 5: Go to step 2
Step 8: Exit
.
Pseudocode of Linear Search Algorithm
1. Start
2. linear_search ( Array , value)
6. end if
7. end for
8. end
Example:
Consider the following list of elements and the element to be searched...
15
.
16
Program:
#include <stdio.h> Output:
scanf("%d",&a[i]);
}
printf("Enter the element to be searched ");
scanf("%d", &element);
found = 1;
break;
}
}
if(found==0)
{
printf("Element is not found in the array\n");
}
}
18
BINARY SEARCH:
• Binary search is the search technique which works efficiently on the sorted lists. Hence, in order
to search an element into some list by using binary search technique, we must ensure that the list
is sorted.
• Binary search follows divide and conquer approach in which, the list is divided into two halves
and the item is compared with the middle element of the list. If the match is found then, the
location of middle element is returned otherwise, we search into either of the halves depending
upon the result produced through the match.
Algorithm:
Step 1 - Read the search element from the user.
Step 2 - Find the middle element in the sorted list.
Step 3 - Compare the search element with the middle element in the sorted list.
Step 4 - If both are matched, then display "Given element is found!!!" and terminate the function.
Step 5 - If both are not matched, then check whether the search element is smaller or larger than
the middle element.
Step 6 - If the search element is smaller than middle element, repeat steps 2, 3, 4 and 5 for the left
sublist of the middle element.
Step 7 - If the search element is larger than middle element, repeat steps 2, 3, 4 and 5 for the right
sublist of the middle element.
Step 8 - Repeat the same process until we find the search element in the list or until sublist
contains only one element.
Step 9 - If that element also doesn't match with the search element, then display "Element is not
found in the list!!!" and terminate the function.
Example:
19
Example 2:
20
#include<stdio.h>
#include<conio.h>
void main()
{
int a[10],i,n,key,flag=0,low,high,mid;
clrscr();
printf("\n Enter the size of an array: ");
scanf("%d",&n);
21
SORTINGS:
Internal Sorting: When all the data that is to be sorted can be accommodated at a time in the
main memory (Usually RAM). Internal sortings has five different classifications: insertion,
selection, exchanging, merging, and distribution sort
External Sorting: When all the data that is to be sorted can’t be accommodated in the memory
(Usually RAM) at the same time and some have to be kept in auxiliary memory such as hard disk,
floppy disk, magnetic tapes etc.
Ex: Natural, Balanced, and Polyphase.
INSERTION SORT:
In Insertion sort the list can be divided into two parts, one is sorted list and other is unsorted list.
In each pass the first element of unsorted list is transfers to sorted list by inserting it in appropriate
position or proper place.
The similarity can be understood from the
style we arrange a deck of cards. This sort
works on the principle of inserting an
22
element at a particular position, hence the
name Insertion Sort.
Following are the steps involved in insertion sort:
1. We start by taking the second element of the given array, i.e. element at index 1, the key. The
key element here is the new card that we need to add to our existing sorted set of cards
2. We compare the key element with the element(s) before it, in this case, element at index 0:
o If the key element is less than the first element, we insert the key element before the first
element.
o If the key element is greater than the first element, then we insert it after the first element.
3. Then, we make the third element of the array as key and will compare it with elements to it's left
and insert it at the proper position.
4. And we go on repeating this, until the array is sorted.
Example 1:
Example 2:
23
Program:
#include<stdio.h>
int main()
{
int n,a[30],key,i,j,temp;
printf("Enter total elements:\n");
scanf("%d",&n);
printf("Enter elements:\n"); Output:
for(i=0;i<n;i++) Enter total elements:10
scanf("%d",&a[i]); Enter elements:
for(i=1;i<n;i++) 6 3 4 7 9 0 1 11 10 8
{ After sorting elements
j=i; are:
while(j>0 && a[j]<a[j-1]) 0 1 3 4 6 7 8 9 10 11
{
temp=a[j];
a[j]=a[j-1];
a[j-1]=temp;
j--;
}
}
printf("After sorting elements are:\n");
for(i=0;i<n;i++)
printf(" %d",a[i]);
return 0;
}
SELECTION SORT:
Given a list of data to be sorted, we simply select the smallest item and place it in a sorted list.
These steps are then repeated until we have sorted all of the data.
In first step, the smallest element is search in the list, once the smallest element is found, it is
exchanged with the element in the first position.
Now the list is divided into two parts.
One is sorted list other is unsorted list.
Find out the smallest element in the
unsorted list and it is exchange with the
starting position of unsorted list, afterthat
it will added in to sorted list.
This process is repeated until all the elements are sorted.
Ex: asked to sort a list on paper.
24
Algorithm:
SELECTION SORT(ARR, N)
Step 1: Repeat Steps 2 and 3 for K = 1 to N-1
Step 2: CALL SMALLEST(ARR, K, N, Loc)
Step 3: SWAP A[K] with ARR[Loc]
Step 4: EXIT
Example 1:
25
Example 2: Consider the elements 23,78,45,88,32,56
Time Complexity:
Number of elements in an array is ‘N’
Number of passes required to sort is ‘N-1’
Number of comparisons in each pass is 1st pass N-1, 2nd Pass N-2 …
Time required for complete sorting is:
T(n) <= (N-1)*(N-1)
T(n) <= (N-1)2
Finally, The time complexity is O(n2).
PROGRAM:
#include <stdio.h>
int main()
{
int a[100], n, i, j, position, t;
26
{
if (a[position] > a[j]) OUTPUT:
position = j; Enter number of elements
} 6
if (position != i) Enter 6 integers
{ 60
t = a[i]; 30
a[i] = a[position]; 20
a[position] = t; 9
} 27
} 34
Sorted list in ascending order:
printf("Sorted list in ascending order:\n"); 9
20
for (i = 0; i < n; i++) 27
printf("%d\n", a[i]); 30
34
return 0; 60
}
BUBBLE SORT:
Bubble sort starts with very first two elements, comparing them to check which one is greater.
In this case, value 33 is greater than 14, so it is already in sorted locations. Next, we compare 33
27
with 27. We find that 27 is smaller than 33 and these two values must be swapped.
Next we compare 33 and 35. We find that both are in already sorted positions.
Then we move to the next two values, 35 and 10. We know then that 10 is smaller 35.
We swap these values. We find that we have reached the end of the array. After one iteration, the
array should look like this −
To be defined, we are now showing how an array should look like after each iteration. After the
second iteration, it should look like this
Notice that after each iteration, at least one value moves at the end.
And when there's no swap required, bubble sorts learns that an array is completely sorted.
Example 2:
28
Algorithm:
BUBBLE SORT(ARR, N)
Step 1: Read the
array elements
Step 2: i:=0;
Step 3: Repeat step 4 and
step 5 until i<n Step 4:
j:=0;
Step 5: Repeat step 6
until j<(n-1)-i Step 6:
if A[j] > A[j+1]
Swap(A[j],A[j+1])
End if
End loop 5
End loop 3
Step 7: EXIT
Time Complexity:
Number of elements in an array
is ‘N’ Number of passes
required to sort is ‘N-1’
Number of comparisons in each pass is 1st pass N-1, 2nd
Pass N-2 … Time required for complete sorting
is:
T(n) <= (N-1)*(N-1) T(n) <= (N-1)2
Finally, The time complexity
is O(n2).
29
Program:
#include<stdio.h>int main()
{
int n,temp,i,j,a[20];
printf("Enter total numbers of elements:\n");
scanf("%d", &n);
printf("Enter elements:\n");
for(i=0;i<n; i++) scanf("%d", &a[i]);
for(i=0;i<n; i++)
{
for(j=0;j<n-1;j++)
{
if(a[j]>a[j+1])
{
temp=a[j]; a[j]=a[j+1];
a[j+1]=temp;
}
}
}
printf("After sorting elements are:\n");for(i=0;i<n;i++)printf("
%d",a[i]);
return 0;
}
Output:
Enter total numbers of elements:
10Enter elements:
6438901527
After sorting elements are: 0 1 2 3 4 5 6 7 8 9
30
UNIT II
Q). What is Linked List? Explain single Linked List and its operations?
Linked List:A linked list is a linear data structure that includes a series of connected nodes. Here,each node stores
the data and address of the next node. It is also a dynamic data structure.
For example,
Types of Linked Lists: There are different linked lists. They are:
Q) 1)Single linked list (or) One way chain: Singly linked list can be defined as the collection ofordered set
of elements. The number of elements may vary according to need of the program. A node in the singly linked
list consists of two parts: data part and link part. Data part of the node stores actual information that is to be
represented by the node while the link part of the node stores the address of its immediate successor.
Structure of the Single Linked List: The representation of memory in single linked list is as follows:
Syntax:
struct node
{
int data;
struct node *next;
}
The next address, which is used to access the next node is known as a pointer. The entire linked list
can be referred and accessed by a head pointer which points to the first node of the list. It is a list identifier,
which contains the address of the first element of the list.
Operations on Single Linked List: The linked list has several operations they are:
1. Create
2. Insertion
a. Insert at begin
b. Insert at Location
c. Insert at end
3. Deletion
a. Delete at begin
b. Delete at Location
c. Delete at End
4. Search
5. Traversal
6. Updating
7. Sorting
8. Merging
9. Displaying
1. Create Operation: Consider the items 10,20,30 and 40 to generate a linked list.The
Representation of singly Linked List for the above items is as follows:
Program:
#include<stdio.h>
#include<stdli.h>
struct Node
{
int data;
struct Node *link;
}*temp;
struct Node
*HEAD,*ptr,*ptr1; void
create(int n)
{
temp=(struct Node*)malloc(sizeof(struct
Node)); temp->data=n;
temp->link=NULL;
if(HEAD==NULL)
{
}
els e
{
}
}
HEAD=temp; ptr=HEAD;
ptr->link=temp; ptr=temp;
void display()
{
ptr=HEAD; if(ptr==NULL)
printf("\nList is Empty");
else
{
while(ptr!=NULL)
{
printf("%d",ptr->data);
printf("-->");
ptr=ptr->link;
}
printf("NULL");
}
}
int main()
{
int ch,i,m,n;
while(1)
{
printf("\n**** MAIN MENU ****");
printf("\n1:CREATE\n2:DISPLAY\n3:EXIT\n
"); printf("\nEnter Your Choice:");
scanf("%d",&ch);
switch(ch)
{
case 1:
printf("\n Enter total no of
Elements:"); scanf("%d",&m);
printf("\n Enter elements:");
for(i=1;i<=m;i++)
{
scanf("%d",&n);
create(n);
}
break;
case 2:
display();
break;
case 3:
return 0;
}
}
return 0;
}
Output:
Enter elements:10 20 30 40 50 60 70
2. Insertion Operation: Using this operation we can insert a value at different positions of the list. They
are:
a) insert at Begin
b) insert at Middle
c) insert at End
a) Insert at Begin: If we insert new value at beginning of the list, the head will be changed to newnode.
b) Insert at Middle: If we insert new value at middle(particular position) of the list, the pointer ofprevious
node is connecting to new node.
c) Insert at End: If we insert new value at End of the list, the pointer address of new nodeis NULL.
Program:
#include<stdio.h>
#include<stdlib.h>
struct Node
{
int data;
struct Node *link;
}*temp;
struct Node
*HEAD,*ptr,*ptr1; void
create(int n)
{
temp=(struct Node*)malloc(sizeof(struct Node));
temp->data=n;
temp->link=NULL;
if(HEAD==NULL)
{
}
else
{
}
}
HEAD=temp; ptr=HEAD;
ptr->link=temp; ptr=temp;
void insert()
{
temp=(struct Node*)malloc(sizeof(struct Node));
ptr1=NULL;
ptr=HEAD;
int count=1,pos,ch,n;
printf("\nEnter an Element:");
scanf("%d",&n);
temp->data=n; temp-
>link=NULL;
printf("\nINSERT AS\n1:AT THE FRONT\n2:AT THE END\n3:AT ANY OTHER POSITION");
printf("\nEnter Your Choice:");
scanf("%d",&ch);
switch(ch)
{
case 1:
temp->link=HEAD;
HEAD=temp; break;
case 2:
while(ptr->link!=NULL)
ptr=ptr->link;
ptr->link=temp;
break;
case 3:
printf("\nEnter the Position to
Insert:"); scanf("%d",&pos);
while(count!=pos)
{
ptr1=ptr;
ptr=ptr-
>link;
count++;
}
if(count==pos)
{
ptr1->link=temp;
temp->link=ptr;
}
break;
}
}
void display()
{
ptr=HEAD;
if(ptr==NULL)
printf("\nList is
Empty"); else
{
while(ptr!=NULL)
{
printf("%d",ptr->data);
printf("--
>");
ptr=ptr-
>link;
}
printf("NULL");
}
}
int main()
{
int ch,i,m,n;
while(1)
{
printf("\n**** MAIN MENU ****");
printf("\n1:CREATE\n2:INSERT\n3:DISPLAY\n4:EXIT\
n"); printf("\nEnter Your Choice:");
scanf("%d",&ch)
; switch(ch)
{
case 1:
printf("\n Enter total no of
Elements:"); scanf("%d",&m);
printf("\n Enter elements:");
for(i=1;i<=m;i++)
{
scanf("%d",&n);
create(n);
}
break;
case 2:
insert();
break;
case 3:
display();
break;
case 4:
exit(0);
}
}
return 0;
}
6
Output:
Enter total no of
Elements:5 Enter
elements:10 20 30 40 50
**** MAIN MENU
**** 1:CREATE
2:INSERT
3:DISPLAY
4:EXIT
7
Enter Your
Choice:2 Enter an
Element:70
INSERT AS
1:AT THE FRONT
2:AT THE END
3:AT ANY OTHER POSITION
Enter Your Choice:2
3. Deletion
Operation: Using this operation we can delete a value at different positions of the list. They are:
a) Delete at Begin
b) Delete at Middle
c) Delete at End
a) Delete at Begin: If we delete the first element of the list, the head will be changed to nextnode.
8
b) Delete at Middle: If we delete middle element of the list, the previous node of deleted node is
connecting to next node of the deleted node.
c) Delete at End: If we delete End element of the list, the previous node of deleted node hasbecome
NULL pointer.
Program:
#include<stdio.h>
#include<stdlib.h>
struct Node
{
int data;
struct Node *link;
}*temp;
struct Node
*HEAD,*ptr,*ptr1; void
create(int n)
{
temp=(struct Node*)malloc(sizeof(struct Node));
temp->data=n;
temp->link=NULL;
if(HEAD==NULL)
{
}
else
{
}
}
HEAD=temp;
ptr=HEAD;
ptr->link=temp; ptr=temp;
void delet()
{
ptr1=NULL;
int ch,pos,count=1;
9
ptr=HEAD;
printf("\nDELETE AS \n1:AT THE FRONT\n2:AT THE END\n3:AT ANY OTHER POSITION");
printf("\nEnter Your Choice:");
scanf("%d",&ch);
switch(ch)
{
case 1:
if(HEAD!=NULL)
{
printf("\nDeleted Element is: %d",HEAD->data);
HEAD=HEAD->link;
}
break;
case 2:
while(ptr->link!=NULL)
{
ptr1=ptr;
ptr=ptr->link;
}
printf("\nDeleted Element is: %d",ptr->data);
ptr1->link=NULL;
break;
case 3:
printf("\nEnter th
break;
case 2:
delet();
break;
case 3:
display();
break;
case 4:
exit(0);
}
}
return 0;
}
Output:
11
4. Search Operation: using this operation we can search particular element in the list.
5. 5.Traveral operation: This operation is performed to visit all node in the list. Also for printingall
elements in the list.
6. Upadating operation: This operation is used to insert new value in the place of existing valuein the list.
7. Sorting Operation: This operation is used to sort the list elements in ascending or descendingorder.
8. Merging Operation: This operation is used to combined more than one list into single list.
9. Displying operation: it is used to display all elements in the list.
Applications of Single Linked List: Linked list is used in a wide variety of applications suchas:
Advantages of Singly Linked List: There are some advantages of singly Linked List
12
to an array.
Disadvantages of Singly Linked List: The disadvantages of singly Linked List are following:
1. Accessing the preceding node of a current node is not possible as there is no backwardtraversal.
2. The Accessing of a node is very time-consuming.
Q) What is Doubly Linked List? Explain Doubly Linked List and itsoperations?
Doubly linked list:
The drawback of singly linked list is we cannot traverse the list backwards
To Traverse the list in reverse direction and forward direction the node should have two
pointers
So we define a structure for a node, which contains three fields, in which one field is data field
and other two are address fields. One is left address and another one is rightaddress.
A list contains this type of nodes is known as doubly linked list or two-way list
Structure of the Double Linked List:
Advantages Of DLL:
Reversing the doubly linked list is very easy.
It can allocate or reallocate memory easily during its execution.
As with a singly linked list, it is the easiest data structure to implement.
The traversal of this doubly linked list is bidirectional which is not possible in a singly linked list.
Deletion of nodes is easy as compared to a Singly Linked List. A singly linked list deletion requires
a pointer to the node and previous node to be deleted but in the doubly linked list, it only required
the pointer which is to be deleted.
Disadvantages Of DLL:
It uses extra memory when compared to the array and singly linked list.
Since elements in memory are stored randomly, therefore the elements are accessed sequentially no
direct access is allowed.
Operations on Doubly Linked List:
1. Create
2. Insert
a. Insert at begin
b. Insert at Location
c. Insert at end
3. Delete
a. Delete at begin
b. Delete at Location
c. Delete at End
4. Merge
5. Search
6. Sort
7. Display
13
1. Create operation:
Example: consider the 3 elements 10,20,30and the representaion of Doubly Linked List forthese 3
elements is as follows:
1. Insert operation: For inserting a new element to the list, we have three positions. They are:
i. insert at Begin
ii. insert at Middle
iii. insert at End
i. insert at Begin: If we insert new element 40 at beginning of the above list, the list is asfollows:
ii. insert at Middle: If we insert new element 40 at middle of the above list, the list is as
follows:
iii. insert at End: If we insert new element 40 at End of the above list, the list is as follows:
14
program
#include<stdio.h>
#include<stdlib.h>
struct node
int data;
};
void main ()
int choice,item;
do
scanf("%d",&item);
insertbeginning(item);
scanf("%d",&choice);
}while(choice == 0);
printf("\nOVERFLOW");
else
if(head==NULL)
ptr->next = NULL;
ptr->prev=NULL;
ptr->data=item;
head=ptr;
else
ptr->data=item;
ptr->prev=NULL;
ptr->next = head;
head->prev=ptr;
head=ptr;
Output
16
Press 0 to insert more ?
0
Output
2. Deletion operation: For deleting an element from the list, we have three positions. Theyare:
i. Delete at Begin
ii. Delete at Middle
iii.Delete at End
i. Delete at Begin: If we delete an element at beginning of the above list, the list is as follows:
ii.Delete at Middle: If we delete an element at middle of the above list, the list is as follows
ii. Delete at End: If we delete an element at End of the above list, the list is as follows:
17
What is Circular Linked List? Explain Circular Linked List and itseperations?
Circular Linked List:In a single list, once we traverse from one node to another is becomesdifficult to get
back as it links the entire nodes in one direction that is forward direction. To overcome this drawback, we
can move on to circular linked lists where the last node holds the address of the first node. The operation
Operations on Circular Linked List: This linked list has several operations they are:
1. Create
2. Insert
a. Insert at begin
b. Insert at Location
c. Insert at end
3. Delete
a. Delete at begin
b. Delete at Location
c. Delete at End
4. Merge
5. Search
6. Sort
7. Display
1. Create Operation: Consider the items 10,20,30,40 and to generate a Circular linked list.The
Representation of Circular Linked List for the above items is as follows:
2. Insertion Operation: Using this operation we can insert a Node at different positions of thelist. They
are:
a) insert at Begin
b) insert at Middle
c) insert at End
a) Insert at Begin: If we insert new value at beginning of the list, the head will be changed to newnode.
And last node will pointing to newly inserted node.
18
b) Insert at Middle: If we insert new value at middle(particular position) of the list, the pointer
addresses are changed for previous and next node of the new node.
c) Insert at End: if we insert new value at end of the list, it is pointing head node.
Program
include<stdio.h>
#include<stdlib.h>
void beg_insert(int);
struct node
int data;
};
void main ()
{
19
int choice,item;
do
scanf("%d",&item);
beg_insert(item);
scanf("%d",&choice);
}while(choice == 0);
if(ptr == NULL)
printf("\nOVERFLOW");
else
if(head == NULL)
head = ptr;
}
20
else
temp = head;
while(temp->next != head)
temp = temp->next;
ptr->next = head;
head = ptr;
printf("\nNode Inserted\n");
Output
Node Inserted
Node Inserted
3. Delete Operation: Using this operation we can delete a Node at different positions of thelist. They
are:
a) Delete at Begin
b) Delete at Middle
c) Delete at End
a) Delete at Begin: If we Delete a value at beginning of the list, the head will be changed to nextnode. And
21
the last node is pointing to next of the deleted node.
b) Delete at Middle: If we Delete a value at middle(particular position) of the list, the pointer
addresses are changed for previous and next node of the delete node.
c) Delete at End: If we Delete a value at end of the list, the previous node of deleted node ispointing to
Head node .
22
Linked-List
1. Image viewer – Previous and next images are linked and can be accessed by the next and previous buttons.
2. Previous and next page in a web browser – We can access the previous and next URL searched in a web
browser by pressing the back and next buttons since they are linked as a linked list.
3. Music Player – Songs in the music player are linked to the previous and next songs. So you can play songs
either from starting or ending of the list.
4. GPS navigation systems- Linked lists can be used to store and manage a list of locations and routes,
allowing users to easily navigate to their desired destination.
5. Robotics- Linked lists can be used to implement control systems for robots, allowing them to navigate and
interact with their environment.
6. Task Scheduling- Operating systems use linked lists to manage task scheduling, where each process
waiting to be executed is represented as a node in the list.
7. Image Processing- Linked lists can be used to represent images, where each pixel is represented as a node
in the list.
8. File Systems- File systems use linked lists to represent the hierarchical structure of directories, where each
directory or file is represented as a node in the list.
9. Symbol Table- Compilers use linked lists to build a symbol table, which is a data structure that stores
information about identifiers used in a program.
10. Undo/Redo Functionality- Many software applications implement undo/redo functionality using linked
lists, where each action that can be undone is represented as a node in a doubly linked list.
11. Speech Recognition- Speech recognition software uses linked lists to represent the possible phonetic
pronunciations of a word, where each possible pronunciation is represented as a node in the list.
12. Polynomial Representation- Polynomials can be represented using linked lists, where each term in the
polynomial is represented as a node in the list.
13. Simulation of Physical Systems- Linked lists can be used to simulate physical systems, where each
element in the list represents a discrete point in time and the state of the system at that time.
23
UNIT III-STACK
Peeking doesn't alter the stack's structure; it only provides information about the top
element.
1
Push operation: it is used to insert new value into a stack
Step1: if we push ‘10’ value into a stack, then the STACK is as follows..
Step2: if we push ‘20’ value into a stack, then the STACK is as follows..
Step3: if we push ‘30’ value into a stack, then the STACK is as follows..
Step4: if we push ‘40’ value into a stack, then the STACK is as follows..
Step5: if we push ‘50’ value into a stack, then the STACK is as follows..
2
Step6: if we push ‘60’ value into a stack, then the STACK displays the message called “STACK
OVERFLOW”. Because the stack max size is 5. When the TOP reaches maximum size, the stack
displays OVERFLOW. So we have to stop the push operations.
POP operation: when we call pop() method the top position item will be removed and top
will be decremented by 1. When we remove the elements at stack top position will be moved
down up to -1. When top reaches -1 then the stack is empty.
Step1: if we Pop ‘50’ value from the stack, then the STACK is as follows..
Step2: if we Pop ‘40’ value from the stack, then the STACK is as follows..
Step3: if we Pop ‘30’ value from the stack, then the STACK is as follows..
Step4: if we Pop ‘20’ value from the stack, then the STACK is as follows..
Step5: if we Pop ‘10’ value from the stack, then the STACK is as follows..
3
Hence the TOP reaches -1 position, now the STACK IS EMPTY.
void push ()
{
int val;
if (top == n )
printf("\n Overflow");
4
else
{
printf("Enter the value?");
scanf("%d",&val);
top = top +1;
stack[top] = val;
}
}
void pop ()
{
if(top == -1)
printf("Underflow");
else
top = top -1;
}
void show()
{
printf(“\nTHE ELEMENTS OF STACK are…\n”);
for (i=top;i>=0;i--)
{
printf("%d\n",stack[i]);
}
if(top == -1)
{
printf("Stack is empty");
}
}
To implement a stack using single linked list concept, all the single linked list operations
perform based on Stack operations of LIFO (last in first out) technique.
In linked list the storing information in the form of nodes and we need to follow the stack
rules.
The top variable is used to insert and delete the elements in the stack.
In linked list implementation of a stack, every new element is inserted as 'top' element.
That means every newly inserted element is pointed by 'top'.
Whenever we want to remove an element from the stack, simply remove the node which
is pointed by 'top' by moving 'top' to its next node in the list.
The next field of the first element must be always NULL.
Example:
consider the STACK with 3 elements, 10,20, 30.
the top value is 30, it is at index number 2. So top=2.
for this stack, the linked list representation is give below:
5
PUSH Operation:
if we push ‘40’ value into a stack, then the STACK and LINKED LIST is as follows..
In the above diagram, the TOP is incremented by 1 position, that is top=2 is changed to
top=3 when we push a new element 40 into a STACK.
Also in linked list, the TOP is changed from 200 to 300.
POP Operation:
if we pop ‘40’ value from the stack, then the STACK and LINKED LIST is as follows..
In the above diagram, the TOP is decremented by 1 position, that is top=3 is changed to top=2
when we pop an element 40 from the STACK.
Also in linked list, the TOP is changed from 300 to 200.
6
Example: C program to implement Stack operations using Linked List.
#include<stdio.h>
#include<stdlib.h>
void push();
void pop();
void display();
struct node
{
int val;
struct node *next;
};
struct node *head;
void main ()
{
int choice=0;
printf("\n*********Stack operations using linked list*********\n");
printf("\n \n");
while(choice != 4)
{
printf("\n\nChose one from the below options...\n");
printf("\n1.Push\n2.Pop\n3.Show\n4.Exit");
printf("\n Enter your choice \n");
scanf("%d",&choice);
switch(choice)
{
case 1:
{
push();
break;
}
case 2:
{
pop();
break;
}
case 3:
{
display();
break;
}
case 4:
{
printf("Exiting ");
break;
}
default:
{
printf("Please Enter valid choice ");
}
};
7
}
}
void push ()
{
int val;
struct node *ptr = (struct node*)malloc(sizeof(struct node));
if(ptr == NULL)
{
printf("not able to push the element");
}
else
{
printf("Enter the value");
scanf("%d",&val);
if(head==NULL)
{
ptr->val = val;
ptr -> next = NULL;
head=ptr;
}
else
{
ptr->val = val;
ptr->next = head;
head=ptr;
}
printf("Item pushed");
}
}
void pop()
{
int item;
struct node *ptr;
if (head == NULL)
{
printf("Underflow");
}
else
{
item = head->val;
ptr = head;
head = head->next;
free(ptr);
printf("Item popped");
}
}
void display()
{
int i;
struct node *ptr; ptr=head;
if(ptr == NULL)
8
{
printf("Stack is empty\n");
}
else
{
printf("Printing Stack elements \n");
while(ptr!=NULL)
{
printf("%d\n",ptr->val);
ptr = ptr->next;
}
}
}
Infix to prefix
Infix to postfix
Prefix to Infix
Prefix to Postfix
Postfix to Infix
Postfix to Infix
9
4. Memory management: The assignment of memory takes place in contiguous memory
blocks. We call this stack memory allocation because the assignment takes place in the function
call stack. The size of the memory to be allocated is known to the compiler. When a function is
called, its variables get memory allocated on the stack. When the function call is completed, the
memory for the variables is released. All this happens with the help of some predefined routines
in the compiler. The user does not have to worry about memory allocation and release of stack
variables.
Consider the following snippet:
int main()
{
// All these variables get memory // allocated on stack
int f;
int a[10];
int c = 20;
int e[n];
}
The memory to be allocated to these variables is known to the compiler and when the function is
called, the allocation is done and when the function terminates, the memory is released.
5. Backtracking Problems: Consider the N-Queens problem for an example. The solution of
this problem is that N queens should be positioned on a chessboard so that none of the queens
can attack another queen. In the generalized N-Queens problem, N represents the number of
rows and columns of the board and the number of queens which must be placed in safe positions
on the board.
10
11
Example: C Program that uses stack operations to evaluate postfix expression
#include<stdio.h>
#include<ctype.h>
int stack[20];
int top = -1;
void push(int x)
{
stack[++top] = x;
}
int pop()
{
return stack[top--];
}
int main()
{
char exp[20];
char *e;
int n1,n2,n3,num;
printf("Enter the expression :: ");
scanf("%s",exp);
e = exp;
while(*e != '\0')
{
if(isdigit(*e))
{
num = *e - 48;
push(num);
}
else
{
n1 = pop();
n2 = pop();
switch(*e)
{
12
case '+':
{
}
case '-':
{
n3 = n1 + n2;break;
n3 = n2 - n1;break;
case '*':
{
n3 = n1 * n2;break;
}
case '/':
{
n3=n2/n1;break;
}
}
push(n3);
}
e
+
+
;
}
printf("\n The result of expression %s =
%d\n\n",exp,pop());
return 0;
}
In the above figure, green is the start point, blue is the intermediate
point, red are points with no feasible solution, grey is the end solution.
14
Algorithm
Following is the algorithm for backtracking −
1. Start
2. if current_position is goal, return success.
3. else
4. if current_position is an end point, return failed.
5. else-if current_position is not end point, explore and repeat above steps.
6. Stop
Complexity of Backtracking
Generally, the time complexity of backtracking algorithm is exponential
(0(kn)). In some cases, it is observed that its time complexity is factorial
(0(N!)).
Hamiltonian Cycle
M-Coloring Problem
N Queen Problem
Rat in Maze Problem
Crypt arithmetic Puzzle
Subset Sum Problem
Sudoku Solving Algorithm
15
Knight-Tour Problem
Tug-Of-War Problem
Word Break Problem
Maximum number by swapping problem
Output:
Approach:
Let’s think about how a stack works.
It follows the LIFO(last in first out) principle. This means the element inserted at the
last will be accessible to us. And similarly, if we remove elements from the stack, we
will get them in the reverse order of insertion. This is exactly what we need.
So, due to its LIFO property, a stack is able to store elements in reverse order of their
insertion and hence can be used to solve our problem.
Can you think of a case where we don’t need to reverse a linked list?
In case, the linked list is empty or has only one node, reversing the linked list won’t
make any change. So, in that case, we don’t reverse it. In all other cases, we need to
reverse the linked list.
Let’s see how to implement our idea.
Algorithm:
Check if the linked list is empty or has a single node. If yes, then no need to
reverse it and simply return from the function. Otherwise, follow the below
steps.
Declare an empty stack.
Iterate through the linked list and push the values of the nodes into the stack.
Now, after the iteration is complete, the linked list is stored in reverse order in the
stack.
Now, start popping the elements from the stack and iterating through the
linked listtogether, and change the values in the nodes by the values we get
from the stack.
Once the stack is empty, we will have the required reversed linked list.
16
17
UNIT-4
More real-world examples can be seen as queues at the ticket windows and bus-stops.
Types of Queue: There are four different types of queue that are listed as follows –
1. Simple Queue or Linear Queue
2. Circular Queue
3. Priority Queue
4. Double Ended Queue (or Deque)
1. Simple Queue or Linear Queue: Queue is a linear data structure to which insertions
and deletions are done from two ends called front and rear. Insertions are done from one
end called rear and deletions are done from other end is called front. It follows First In First
Out(FIFO) technique. i.e., the data item stored first will be accessed first.
The representation of the Linear queue is shown in the below image –
2. Circular Queue: Circular Queue is a linear data structure in which the operations are
performed based on FIFO (First In First Out) principle and the last position is connected back
to the first position to make a circle. It is also called ‘Ring Buffer’.
In linear Queues once the element is deleted from queue, that location cannot be filled. So the
drawback of linear queue is wastage of memory. This problem can be solved by circular queue.
The representation of the Circular queue is shown in the below image –
1
Priority Queue: It is a special type of queue in which the elements are arranged
based onthe priority. It is a special type of queue data structure in which every
element has a priority associated with it. Suppose some elements occur with the
same priority, they will be arranged according to the FIFO principle. The
representation of priority queue is shown in the below image -
Queue is a linear data structure to which insertions and deletions are done
from two ends called front and rear. Insertions are done from one end called
rear and deletions are done from other end is called front. It follows First In
First Out(FIFO) technique. i.e., the data item stored first will be accessed
first.
The technical name from inserting an element into the queue is called
‘Enqueue’ and deleting an element from the queue is called ‘Dequeue’.
2
A real-world example of queue can be a single-lane one-way road, where the
vehicle enters first, exits first.
More real-world examples can be seen as queues at the ticket windows and bus-
stops.
Structure of QUEUE:
Step2: if we insert ‘20’ value into a QUEUE, then the QUEUE is as follows..
3
Step3: if we insert ‘30’ value into a QUEUE, then the QUEUE is as follows..
Step4: if we insert ‘40’ value into a QUEUE, then the QUEUE is as follows..
Step5: if we insert ‘50’ value into a QUEUE, then the QUEUE is as follows..
Step5: if we try to insert ‘60’ value into a QUEUE, then the message displays as QUEUEIS
FULL.
Dequeue operation: The Dequeue operation is used to delete the element at the front end
ofthe queue.
Step1: if we delete ‘10’ value from the QUEUE, then the QUEUE is as follows..
Step2: if we delete ‘20’ value from the QUEUE, then the QUEUE is as follows..
Step3: if we delete ‘30’ value from the QUEUE, then the QUEUE is as follows..
4
Step4: if we delete ‘40’ value from the QUEUE, then the QUEUE is as follows..
Step4: if we delete ‘50’ value from the QUEUE, then the QUEUE is as follows..
When we remove the ‘50’ element from the queue, the front and rear will becomes to -
1 positionand QUEUE becomes to empty.
#include<stdio.h>
#include<stdlib.h>
#define maxsize 5
void insert();
void delete();
void display();
int front = -1, rear = -1;
int queue[maxsize];
void main ()
{
int choice;
while(choice != 4)
{
printf("\n*************************Main
Menu*****************************\n");
printf("\n===========================================
======================\n");
printf("\n1.insert an element\n2.Delete an element\n3.Display the
queue\n4.Exit\n");
printf("\nEnter your choice ?");
scanf("%d",&choice);
5
switch(choice)
{
case 1:
insert();
break;
case 2:
delete();
break;
case 3:
display();
break;
case 4:
exit(0);
break;
default:
printf("\nEnter valid choice??\n");
}
}
}
void insert()
{
int item;
printf("\nEnter the element\n");
scanf("\n%d",&item);
if(rear == maxsize-1)
{
printf("\nOVERFLOW\n");
return;
}
if(front == -1 && rear == -1)
{
front = 0;
rear = 0;
}
else
{
rear = rear+1;
}
queue[rear] = item;
printf("\nValue inserted ");
6
}
void delete()
{
int item;
}
else
{
item = queue[front];
if(front == rear)
{
front = -1;
rear = -1 ;
}
else
{
front = front + 1;
}
printf("\nvalue deleted ");
}
}
void display()
{
int i;
if(rear == -1)
{
printf("\nEmpty queue\n");
}
else
{
printf("\nprinting values \n");
for(i=front;i<=rear;i++)
{
printf("\n%d\n",queue[i]);
}
7
}
}
Q3)Explain Representation of Queue using Linked list?
Drawback of Queue using an Array:
linked list the storing information in the form of nodes and we need to follow the
Queue rules.
The rear end is used to insert and front end is used to delete the elements in the
Queue.
In linked list implementation of a Queue, every new element is inserted as 'rear'
element.
That means every newly inserted element is pointed by 'rear'.
Whenever we want to remove an element from the Queue, simply remove
the nodewhich is pointed by 'front' by moving 'front' to its next node in the list.
The next field of the first element must be always NULL.
Operations on Queue using Linked List:
1)Enqueue Operation: Enqueue function will add the element at the end of
the linked list.Using the rear pointer, we can track the last inserted element.
At beginning, the Node Becomes EMPTY. The two pointers have NULL
value. That is.,Front=NULL and rear=NULL
Step1:if we insert ‘10’ value into a QUEUE, then the QUEUE is as follows..
Step2:if we insert ‘20’ value into a QUEUE, then the QUEUE is as follows..
8
Step3:if we insert ‘30’ value into a QUEUE, then the QUEUE is as follows..
1) Dequeue Operation: Dequeue function will delete the element at the begin of
the linked list.Using the front pointer, we can track the first inserted element.
Because the Dequeue operation must follows the FIFO(First In First Out) Technique.
Step1:if we delete ‘10’ value from the QUEUE, the head node 10 is deleted,
and 20 nodebecomes head node. And front pointer moved to 20node. now the
QUEUE is as follows..
Step2:if we delete ‘20’ value from the QUEUE, the head node 20 is deleted,
and 30 nodebecomes head node. And front pointer moved to 30 node. now the
QUEUE is as follows..
Step3:if we delete ‘30’ value from the QUEUE, the QUEUE becomes EMPTY. Then two
pointersbecomes NULL. That is ..,
Front=NULL and rear=NULL.
9
};
struct node *front;
struct node *rear;
void insert();
void delete();
void display();
void main ()
{
int choice;
while(choice != 4)
{
printf("\n*************************Main
Menu*****************************\n");
printf("\n===========================================
======================\n");
printf("\n1.insert an element\n2.Delete an element\n3.Display the
queue\n4.Exit\n");
printf("\nEnter your choice ?");
scanf("%d",& choice);
switch(choice)
{
case 1:
insert();
break;
case 2:
delete();
break;
case 3:
display();
break;
case 4:
exit(0);
break;
default:
printf("\nEnter valid choice??\n");
}
}
}
void insert()
{
10
struct node *ptr; int item;
ptr = (struct node *) malloc (sizeof(struct node));
if(ptr == NULL)
{
printf("\nOVERFLOW\n"); return;
}
else
{
printf("\nEnter value?\n");
scanf("%d",&item);
ptr -> data = item;
if(front == NULL)
{
front = ptr;
rear = ptr;
front -> next = NULL;
rear -> next = NULL;
}
else
{
rear -> next = ptr;
rear = ptr;
rear->next = NULL;
}
}
}
void delete ()
{
struct node *ptr;
if(front == NULL)
{
printf("\nUNDERFLOW\n");
return;
}
else
{
ptr = front;
front = front -> next;
free(ptr);
11
}
}
void display()
{
struct node *ptr; ptr = front;
if(front == NULL)
{
printf("\nEmpty queue\n");
}
else
{
printf("\nprinting values \n");
while(ptr != NULL)
{
printf("\n%d\n",ptr -> data);
ptr = ptr -> next;
}
}
}
12
Buffer’.
In linear Queues once the element is deleted from queue, that location cannot
be filled. So the drawback of linear queue is wastage of memory. This
problem can be solved by circular queue.
Circular queue is a linear list in which once the rear pointer reaches max_size
then it is placed at 0th position. i.e. making the queue is a circular. Similarly,
when the front pointer reaches max_size then it is reset to 0.
Enqueue Operation: The enqueue operation is used to insert the element at the rear end
ofthe Cqueue.
Step1: if we insert ‘10’ value into a CQUEUE, then the CQUEUE is as follows..
Step2: if we insert ‘20’ value into a CQUEUE, then the CQUEUE is as follows..
13
Step3: if we insert ‘30’, ’40’ values into a CQUEUE, then the CQUEUE is as follows..
Step4: if we insert ‘50’, ’60’ values into a CQUEUE, then the CQUEUE is as follows..
Step5: if we try to insert ‘70’ value into a CQUEUE, then the message displays
as CQUEUEISFULL.
Dequeue operation: The Dequeue operation is used to delete the element at the front
end of thecqueue.
Step1: if we delete ‘10’ value from the CQUEUE, then the CQUEUE is as follows..
Step2: if we delete ‘20’ value from the CQUEUE, then the CQUEUE is as follows..
Step3: if we delete ‘30’, ‘40’ values from the CQUEUE, then the CQUEUE is as follows..
14
Circular Queue Behavior:
Step4: if we insert ‘70’ value into a CQUEUE, then the CQUEUE is as follows..
Breadth-first Search:
It uses the queue data structure to find the shortest path in the graph. In this
method, one vertex is selected and marked when it's visited, then its adjacent
vertices are visited and stored in the queue.
Step 2: Insert the first node A and set its status = 2(waiting state).
Step 4: Dequeue a node, process it, and set its status = 3(processed state)
Step 5: Insert all the neighbors of N that are in the ready state(staus=1) and set
their status = 2(waiting state)
15
(END OF LOOP)
Step 6: EXIT
A––B
| |
C––D
Step 1:
This is one of the most common applications of queues where a single resource is
shared among multiple consumers, or asked to perform multiple tasks.
Imagine you requested a task first before your friend, but your friend got the output
first? Wouldn’t you call it a corrupt system? (quite literally!)
17
CPU page replacement algorithm doesn’t let that happen. It lets the operating
system store all the processes in the memory in the form of a queue.
It makes sure that the tasks are performed on the basis of the sequence of requests.
When we need to replace a page, the oldest page is selected for removal,
underlining the First-In-First-Out (FIFO) principle.
Insert pages into the set one by one until the size of the set reaches
capacity or all page requests are processed
Update the pages in the queue to perform First Come-First Serve
Increment page fault
Else
Else
This First Come First Serve (FCFS) method offers both non-
preemptive and pre-emptive scheduling algorithms.
18
FCFS CPU Scheduling
Printer Spooling
Another important example of applications of queues is printer spooling. Now,
what do we mean by printer spooling?
It's crucial to understand from the outset that printers have much less memory than
you might think. Even in this day and age, some only have a few megabytes of
RAM available.
By using printer spooling, we can send one or more large document files to a
printer without having to wait for the current task to be completed. Consider it as a
cache or buffer. It's a location where your papers can "queue up" and prepare for
printing when another printing activity has been finished.
All print tasks in the queue are managed by a program known as a "spooler". It will
send the line of documents to the printer in the sequence they were received using
the First In First Out principle of the queue.
19
If not for spooling, each computer would have to manually wait for the printer to
become accessible. Most people take it for granted because it's handled
automatically in the background.
Spooling can make it simple to delete documents before they are printed because
there is a queue in the order that they were received. You can choose to delete a
particular job from the queue, for example, if you accidentally printed the wrong
page or needed to format it slightly differently. While there could be several ways
to accomplish this, queues provide the most efficient solution.
----------------------------------
Deques
Q1)Explain about DeQue(Double Ended Queue)?
20
Operations of DeQueue:
1. Initialize
2. Insertion at rear
3. Deletion from front
4. Insertion at front
5. Deletion from rear.
6. Full status check
7. Empty status check
Initializing a DeQue: Consider the DeQue
with size is 5 Step1: Empty DeQue
Step2: Inserting ‘20’ element into DeQue, then the Deque is as follows..
Step3: Inserting ‘30’ element into DeQue, then the Deque is as follows..
Step4: Inserting ‘40’ element into DeQue, then the Deque is as follows..
21
Step5: Inserting ‘50’ element into DeQue, then the Deque is as follows..
Step2: Removing ‘20’ element from the DeQue, then the Deque is as follows..
Note: The above insertions and deletions are done as like normal QUEUE. Now we
can see theinsertions and deletions are not doing by the normal QUEUE….they are:
22
Step2: Deleting ‘40’ and ‘30’ elements from Rear end is as follows..
23
No Reallocation: Deques do not require reallocation of memory when
elements are inserted or removed.
Thread Safe: Deques can be thread-safe if used with proper
synchronization.
Cache-Friendly: Deques have a contiguous underlying storage structure
which makes them cache-friendly.
Disadvantages of Deque:
Deque has no fixed limitations for the number of elements they may contain.
This interface supports capacity-restricted deques as well as the deques with
no fixed size limit.
They are less memory efficient than a normal queue.
Memory Overhead: Deques have higher memory overhead compared to
other data structures due to the extra pointers used to maintain the double-
ended structure.
Synchronization: Deques can cause synchronization issues if not used
carefully in multi-threaded environments.
Complex Implementation: Implementing a deque can be complex and
error-prone, especially if implementing it manually.
Not All Platforms: Deques may not be supported by all platforms, and may
need to be implemented manually.
Not Suitable for Sorting: Deques are not designed for sorting or searching,
as these operations require linear time.
Limited Functionality: Deques have limited functionality compared to other
data structures such as arrays, lists, or trees.
24
UNIT-5
TREES
Tree Data Structure is a hierarchical data structure in which a collection of elements known as nodes
are connected to each other via edges such that there exists exactly one path between any two nodes.
A tree data structure is a hierarchical structure that is used to represent and organize data in a way that
is easy to navigate and search. It is a collection of nodes that are connected by edges and has a hierarchical
relationship between the nodes. The topmost node of the tree is called the root, and the nodes below it are called
the child nodes. Each node can have multiple child nodes, and these child nodes can also have their own child
nodes, forming a recursive structure.
Parent Node: The node which is a predecessor of a node is called the parent node of that node. {B} is the parent
node of {D, E}.
Child Node: The node which is the immediate successor of a node is called the child node of that node.
Examples: {D, E} are the child nodes of {B}.
Root Node: The topmost node of a tree or the node which does not have any parent node is called the
root node. {A} is the root node of the tree. A non-empty tree must contain exactly one root node and
exactly one path from the root to all other nodes of the tree.
Leaf Node or External Node: The nodes which do not have any child nodes are called leaf nodes.
Ancestor of a Node: Any predecessor nodes on the path of the root to that node are called Ancestors of
that node. {A,B} are the ancestor nodes of the node {E}
Sibling: Children of the same parent node are called siblings. {D,E} are called siblings.
1
Level of a node: The count of edges on the path from the root node to that node. The root node has
level 0.
Internal node: A node with at least one child is called Internal Node.
Neighbor of a Node: Parent or child nodes of that node are called neighbors of that node.
Binary tree: In a binary tree, each node can have a maximum of two children linked to it. Some common
types of binary trees include full binary trees, complete binary trees, balanced binary trees, and
degenerate or pathological binary trees.
Ternary Tree: A Ternary Tree is a tree data structure in which each node has at most three child nodes,
usually distinguished as “left”, “mid” and “right”.
N-ary Tree or Generic Tree: Generic trees are a collection of nodes where each node is a data structure
that consists of records and a list of references to its children(duplicate references are not allowed).
Unlike the linked list, each node stores the address of multiple nodes.
File System: This allows for efficient navigation and organization of files.
Data Compression: Huffman coding is a popular technique for data compression that involves
constructing a binary tree where the leaves represent characters and their frequency of occurrence. The
resulting tree is used to encode the data in a way that minimizes the amount of storage required.
Compiler Design: In compiler design, a syntax tree is used to represent the structure of a program.
Database Indexing: B-trees and other tree structures are used in database indexing to efficiently search
for and retrieve data.
Binary Search Tree is a data structure used in computer science for organizing and storing data in a
sorted manner. Binary search tree follows all properties of binary tree and its left child contains values less than
the parent node and the right child contains values greater than the parent node. This hierarchical structure
allows for efficient Searching, Insertion, and Deletion operations on the data stored in the tree.
2
Binary Search Tree (BST) is a special type of binary tree in which the left child of a node has a value
less than the node’s value and the right child has a value greater than the node’s value. This property is called
the BST property and it makes it possible to efficiently search, insert, and delete elements in the tree.
3
2. Insert a node into a BST:
A new key is always inserted at the leaf. Start searching a key from the root till a leaf node. Once a leaf node
is found, the new node is added as a child of the leaf node.
4
Implementation of the insertion of a single node in binary search tree
Code:
return current;
}
root->right
8
= deleteNode(root->right, key);
}
9
Binary Search Tree (BST) Traversals – In order, Preorder, Post Order
Given a Binary Search Tree, The task is to print the elements in in order, preorder, and post order
traversal of the Binary Search Tree.
Output:
Inorder Traversal: 10 20 30 100 150 200 300
Preorder Traversal: 100 20 10 30 200 150 300
Postorder Traversal: 10 30 20 150 300 200 100
Input:
Output:
Inorder Traversal: 8 12 20 22 25 30 40
Preorder Traversal: 22 12 8 20 30 25 40
Postorder Traversal: 8 20 12 25 40 30 22
10
Hash Function
The hash function is a function that takes a key and returns an index into the hash table. The goal of a
hash function is to distribute keys evenly across the hash table, minimizing collisions (when two keys map to
the same index).
A hash collision occurs when two different keys map to the same index in a hash table. This can happen
even with a good hash function, especially if the hash table is full or the keys are similar.
Poor Hash Function: A hash function that does not distribute keys evenly across the hash table can lead to
more collisions.
High Load Factor: A high load factor (ratio of keys to hash table size) increases the probability of
collisions.
Similar Keys: Keys that are similar in value or structure are more likely to collide.
Applications of Hashing
Hash tables are used in a wide variety of applications, including:
Databases: Storing and retrieving data based on unique keys
Caching: Storing frequently accessed data for faster retrieval
Symbol Tables: Mapping identifiers to their values in programming languages
Network Routing: Determining the best path for data packets
11
What is Hashing?
Hashing refers to the process of generating a fixed-size output from an input of variable size using the
mathematical formulas known as hash functions. This technique determines an index or location for the storage
of an item in a data structure.
Components of Hashing
There are majorly three components of hashing:
1. Key: A Key can be anything string or integer which is fed as input in the hash function the technique that
determines an index or location for storage of an item in a data structure.
2. Hash Function: The hash function receives the input key and returns the index of an element in an array
called a hash table. The index is known as the hash index.
3. Hash Table: Hash table is a data structure that maps keys to values using a special function called a hash
function. Hash stores the data in an associative manner in an array where each data value has its own unique
index.
12
What is Collision?
The hashing process generates a small number for a big key, so there is a possibility that two keys could
produce the same value. The situation where the newly inserted key maps to an already occupied, and it must be
handled using some collision handling technology.
Collision in Hashing
Advantages of Hashing in Data Structures
Key-value support: Hashing is ideal for implementing key-value data structures.
Fast data retrieval: Hashing allows for quick access to elements with constant-time complexity.
Efficiency: Insertion, deletion, and searching operations are highly efficient.
Memory usage reduction: Hashing requires less memory as it allocates a fixed space for storing elements.
Scalability: Hashing performs well with large data sets, maintaining constant access time.
Security and encryption: Hashing is essential for secure data storage and integrity verification.
separate Chaining:
The idea behind separate chaining is to implement the array as a linked list called a chain. Separate
chaining is one of the most popular and commonly used techniques in order to handle collisions.
13
The linked list data structure is used to implement this technique. So what happens is, when multiple elements
are hashed into the same slot index, then these elements are inserted into a singly-linked list which is known as
a chain.
Here, all those elements that hash into the same slot index are inserted into a linked list. Now, we can use a key
K to search in the linked list by just linearly traversing. If the intrinsic key for any entry is equal to K then it
means that we have found our entry. If we have reached the end of the linked list and yet we haven’t found our
entry then it means that the entry does not exist. Hence, the conclusion is that in separate chaining, if two
different elements have the same hash value then we store both the elements in the same linked list one after
the other.
Example: Let us consider a simple hash function as “key mod 7” and a sequence of keys as 50, 700, 76, 85,
92, 73, 101
Separate Chaining
The idea is to make each cell of the hash table point to a linked list of records that have the same hash
function value. Chaining is simple but requires additional memory outside the table.
Example: We have given a hash function and we have to insert some elements in the hash table using a
separate chaining method for collision resolution technique.
Hash function = key % 5,
Elements = 12, 15, 22, 25 and 37.
Let’s see step by step approach to how to solve the above problem:
14
Step 1: First draw the empty hash table which will have a possible range of hash values from 0 to 4
according to the hash function provided.
Step 2: Now insert all the keys in the hash table one by one. The first key to be inserted is 12 which is
mapped to bucket number 2 which is calculated by using the hash function 12%5=2.
Step 3: Now the next key is 22. It will map to bucket number 2 because 22%5=2. But bucket 2 is already
occupied by key 12.
15
Step 4: The next key is 15. It will map to slot number 0 because 15%5=0.
Step 5: Now the next key is 25. Its bucket number will be 25%5=0. But bucket 0 is already occupied by
key 25. So separate chaining method will again handle the collision by creating a linked list to bucket 0.
Hence In this way, the separate chaining method is used as the collision resolution technique.
Open Addressing
In open addressing, all elements are stored in the hash table itself. Each table entry contains either a
record or NIL. When searching for an element, we examine the table slots one by one until the desired element
is found or it is clear that the element is not in the table.
16
check for next index using key = (key+1) % size
4. Check, if the next index is available hashTable[key] then store the value. Otherwise try for next index.
5. Do the above process till we find the space.
Example: Let us consider a simple hash function as “key mod 5” and a sequence of keys that are to be inserted
are 50, 70, 76, 85, 93.
Step 1: First draw the empty hash table which will have a possible range of hash values from 0 to 4
according to the hash function provided.
Step 2: Now insert all the keys in the hash table one by one. The first key is 50. It will map to slot number
0 because 50%5=0. So insert it into slot number 0.
Step 3: The next key is 70. It will map to slot number 0 because 70%5=0 but 50 is already at slot number 0
so, search for the next empty slot and insert it.
17
Step 4: The next key is 76. It will map to slot number 1 because 76%5=1 but 70 is already at slot number 1
so, search for the next empty slot and insert it.
Step 5: The next key is 85 It will map to slot number 3 because 85%5=0, but 50 is already at slot number 0
so, search for the next empty slot and insert it. So insert it into slot number 3.
18
Step 6: The next key is 93 It will map to slot number 4 because 93%5=3, but 85 is already at slot number 3
so, search for the next empty slot and insert it. So insert it into slot number 4.
This method is also known as the mid-square method because in this method we look for i2‘th
probe (slot) in i’th iteration and the value of i = 0, 1, . . . n – 1. We always start from the original hash
location. If only the location is occupied then we check the other slots.
Let hash(x) be the slot index computed using the hash function and n be the size of the hash table.
If the slot hash(x) % n is full, then we try (hash(x) + 12) % n.
If (hash(x) + 12) % n is also full, then we try (hash(x) + 22) % n.
If (hash(x) + 22) % n is also full, then we try (hash(x) + 32) % n.
This process will be repeated for all the values of i until an empty slot is found
Example: Let us consider table Size = 7, hash function as Hash(x) = x % 7 and collision resolution strategy to
be f(i) = i2 . Insert = 22, 30, and 50
19
Step 2 – Insert 22 and 30
Hash(22) = 22 % 7 = 1, Since the cell at index 1 is empty, we can easily insert 22 at slot 1.
Hash(30) = 30 % 7 = 2, Since the cell at index 2 is empty, we can easily insert 30 at slot 2.
Step 3: Inserting 50
Hash(50) = 50 % 7 = 1
In our hash table slot 1 is already occupied. So, we will search for slot 1+1 2, i.e. 1+1 = 2,
Again slot 2 is found occupied, so we will search for cell 1+2 2, i.e.1+4 = 5,
20
2.c) Double Hashing
Double hashing is a collision resolving technique in Open Addressed Hash tables. Double hashing make use of
two hash function,
The first hash function is h1(k) which takes the key and gives out a location on the hash table. But if the
new location is not occupied or empty then we can easily place our key.
But in case the location is occupied (collision) we will use secondary hash-function h2(k) in combination
with the first hash-function h1(k) to find the new location on the hash table.
where
Example: Insert the keys 27, 43, 692, 72 into the Hash Table of size 7. where first hash-function is h1(k) = k
mod 7 and second hash-function is h2(k) = 1 + (k mod 5)
Step 1: Insert 27
21
Step 2: Insert 43
43 % 7 = 1, location 1 is empty so insert 43 into 1 slot.
22
Step 4: Insert 72
Applications of Hashing
Hashing is a way to add data in any data structure in such a way that it is possible to insert, delete, and
scan the simple operations on that data in O (1) time. Since it optimizes the code to a large degree, it is one of the
most critical things that any programmer and developer should know.
To implement programming languages, file systems, pattern searching, distributed key-value storage,
cryptography, etc., hashing is used. There are a number of cases in which the principle of hashing is used.
There are also other hashing uses, including the hash functions of modern-day cryptography. Here are some of
these applications:
Message Digest
23
Password Verification
Data Structures
Compiler Operation
Rabin-Karp Algorithm
Linking File name and path together
Message Digest:
This is an example of a Hash task for cryptography. The task that generates a result from which it is close
to unfeasible to enter the input are cryptographic hash functions. Irreversibility is considered this property of
hash functions.
Ex:
Suppose the files have to be stored on some of the available cloud providers. You must make sure that no
third party is messing with the files that you keep. You do so using a cryptographic hash algorithm by calculating
the “hash” of the text. SHA 256 is one of the predominant cryptanalysis hash contrivances. The full area of the
hash thus calculated is 32 bytes. So the computation of the hashing huge amounts of files won’t be an issue.
These hashes are saved on your local instruments.
Now, when you copy the files, the hash will be computed again. Then you align it with the computation
of the last hash. So, you wonder whether or not you wonder if the files have been manipulated or not. The hash
price of the file will certainly change if anyone manipulates the file. It is almost difficult to tamper with the file
without modifying the hash.
Password Verification:
In password authentication, cryptanalysis hash task is very widely used. Let’s use an example to view this:
You type your email and password to validate that the account you are attempting to access belongs to you
anytime you use any online service that needs a user username. A hash of the password is calculating as the
password is entered, and is then forwarded to the server for password authentication. The passwords saved on the
server are simply the original passwords’ calculated hash values. This is required to guarantee that no sniffing is
present when the password is transmitted from client to server.
Data Structures:
Various programming tongues provide Data Structures found on the hash table. The main principle is to generate
a key-value twine where a particular rate is meant to be a key, while for different keys the rate may be the same.
This implementation is used in C++ in disordered set & unordered charts, java in HashSet & HashMap, python
enum, etc.
Compiler Operation:
A programming tongues keywords are refined in a different manner than most identifiers. The accumulator adds
all these access. in a collection that is implemented using a hash table to distinguish between the access. of a
programming tongue (if, otherwise, for, back, etc.) and other selectors and to accumulate the software
successfully.
24
Rabin-Karp Algorithm:
The Rabin-Karp contrivance is one of the most common uses of hashing. This is effectively a cord-searching
contrivance used to locate someone set of rules in a cord using hashing. Detecting plagiarism is a realistic
implementation of this algorithm. Go by Looking for Patterns or Set 3 (Rabin-Karp Algorithm) to learn more
about Rabin-Karp.
We notice two very important components of a file when going through data on our local machine, i.e. file name
and file path. The system utilizes a guide (document name, record way), which is actualized utilizing a hash
table, to spare the correspondence between document name and document w
25