0% found this document useful (0 votes)
53 views118 pages

Data Structures r23 Full Material

The document provides an introduction to linear data structures, detailing their types, classifications, and operations. It explains primitive and non-primitive data structures, with a focus on linear structures like arrays, linked lists, stacks, and queues, as well as non-linear structures like trees and graphs. Additionally, it discusses abstract data types (ADTs), their features, and advantages, emphasizing the importance of abstraction and encapsulation in data management.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
53 views118 pages

Data Structures r23 Full Material

The document provides an introduction to linear data structures, detailing their types, classifications, and operations. It explains primitive and non-primitive data structures, with a focus on linear structures like arrays, linked lists, stacks, and queues, as well as non-linear structures like trees and graphs. Additionally, it discusses abstract data types (ADTs), their features, and advantages, emphasizing the importance of abstraction and encapsulation in data management.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 118

INTRODUCTION TO LINEAR DATA STRUCTURES

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.

CLASSIFICATION OF DATA STRUCTURES:

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.

Linear and Non-linear Structures:


 If the elements of a data structure are stored in a linear or sequential order, then it is a linear data
structure.
o Examples include arrays, linked lists, stacks, and queues.
o Linear data structures can be represented in memory in two different ways. One way is to
have to a linear relationship between elements by means of sequential memory locations.
The other way is to have a linear relationship between elements by means of links.

 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.

Insert element into the Queue:

Delete element from Queue:

 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

OPERATIONS ON DATA STRUCTURES:

 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.

Example: Stack ADT


A stack consists of elements of some type arranged in a sequential order
Operations:
Initialize() – initializing it to be empty
Push() – insert an element into the stack
Pop() – delete an element from the stack
isEmpty() – Checks if stack is empty
isFull() – checks if stack is full

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.

 isEmpty() – Return true if the list is empty, otherwise return false.


 isFull() – Return true if the list is full, otherwise return false.

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:

 Algorithm is step by step logical procedure for solving a problem.


 In Algorithm each step is called Instruction.
 An Algorithm is any well-defined computational procedure that take some values as inputs and
produce some values as output.
 An Algorithm is a sequence of computational steps that transform input into output.
 An Algorithm has 5 basic properties:
1. Input:An Algorithm has take ‘0’ or more number of inputs that can be supplied as externally.
2. Output: An Algorithm must produce at least one output.
3. Definiteness: Each instruction in the algorithm must be clear.
4. Finiteness: An algorithm must terminate after a finite number of steps.
5. Effectiveness: Each operation should be effective. i.e the operations must be terminate after
finite amount of time.

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:

 The efficiency of an algorithm can be computed by measuring the performance of an algorithm.


We can measure the performance of an algorithm in Two(2) ways.
1. Time Complexity
2. Space Complexity
1. Time Complexity:
 The time complexity of an algorithm is the amount of computing time required by an algorithm
to run its completion.
 There are 2 types of computing time 1. Compile time 2. Run time

 The time complexity generally computed at run time (or) execution time.
 The time complexity can be calculated in terms of frequency count.
 Frequency count is a count denoting the number of times the statement should be executed.
 The time complexity can be calculated as
Comments – 0
Assignment / return statement – 1
Conditional (or) Selection Constructs – 1

Example 1: Sum of the elements in an Array


Statements Step count/ Execution Frequency Total Steps
Algorithm Addition (A,n) 0 - 0
{ 0 - 0
//A is an array of size ‘n’ 0 - 0
Sum :=0; 1 1 1
for i:=1 to n do 1 n+1 n+1
Sum:=Sum+A[i]; 1 n n
return Sum; 1 1 1
} 0 - 0
Total 2n+3

Example 2: Subtraction of two matrices


Statements Step count/ Execution Frequency Total Steps
Algorithm Subtract (A,B,C,m,n) 0 - 0
{ 0 - 0
for i:=1 to m do 1 m+1 m+1
for j:=1 to n do 1 m(n+1) mn+m
C[i,j] := A[i,j] – B[i,j]; 1 mn mn
} 0 - 0
Total 2mn+2m+1

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.

Example 1: Sum of three numbers


Algorithm Add(a,b,c)
{
//a,b,c are float type variables
return a+b+c;
}
 The space required for this algorithm is: Assume a,b,c are occupies 1 word size each, total size
comes to be 3.

Example 2: Sum of Array values


Algorithm Addition (A,n)
{
//A is an array of size ‘n’
Sum :=0;
for i:=1 to n do
Sum:=Sum+A[i];
return Sum;
}
 The space required for this algorithm is:
One word space for each variable then i,sum,n  3
For Array A[ ] we require the size  n
Total space complexity for this algorithm is S(p) ≥ (n+3)

What to Analyze in an algorithm:


An Algorithm can require different times to solve different problems of same size
1. Worst case: Maximum amount of time that an algorithm require to solve a problem of size ‘n’.
Normally we can take upper bound as complexity. We try to find worst case behavior.
2. Best case: Minimum amount of time that an algorithm require to solve a problem of size ‘n’.
Normally it is not much useful.
3. Average case: the average amount of time that an algorithm require to solve a problem of size ‘n’.
Some times it is difficult to find. Because we have to check all possible data organizations

13
SEARCHING:

 Searching means to find whether a particular value is present in an array or not.


 If the value is present in the array, then searching is said to be successful and the searching process
gives the location of that value in the array.
 However, if the value is not present in the array, the searching process displays an appropriate
message and in this case searching is said to be unsuccessful. 
 Searching techniques are linear search, binary search and Fibonacci Search

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.

Algorithm of the Linear Search Algorithm


Step 1 - Read the search element from the user.
Step 2 - Compare the search element with the first element in the list.
Step 3 - If both are matched, then display "Given element is found!!!" and terminate the function
Step 4 - If both are not matched, then compare search element with the next element in the list.
Step 5 - Repeat steps 3 and 4 until search element is compared with last element in the list.

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 1: Set i to 0 // i is the index of an array which starts from 0

Step 2: if i > n then go to step 7 // n is the number of elements in array

Step 3: if Arr[i] = a then go to step 6


14
Step 4: Set i to i + 1

Step 5: Go to step 2

Step 6: Print element a found at index i and go to step 8

Step 7: Print element not found

Step 8: Exit

.
Pseudocode of Linear Search Algorithm
1. Start
2. linear_search ( Array , value)

3. For each element in the array

4. If (searched element == value)

5. Return's the searched element location

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:

void main() Enter the size of an array


5
{ Enter the elements in
array
int a[10],i,element, found = 0,n; 10
printf("Enter the size of an array\n"); 20
30
scanf("%d",&n); 40
50
printf("Enter the elements in array \n"); Enter the element to be
for (i = 0; i < n; i++) searched 40
Element is found in the
{ array at index location = 3

scanf("%d",&a[i]);
}
printf("Enter the element to be searched ");
scanf("%d", &element);

/* Linear search begins */


for (i = 0; i < n ; i++)
{
if (a[i]==element)
{
printf("Element is found in the array at index location = %d",i);

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);

printf("\n Enter the elements in ascending order: ");


for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
printf("\n Enter the number to be search: ");
scanf("%d",&key);
low=0;
high=n-1;
while(low<=high)
{
mid=(low+high)/2;
if(key==a[mid])
{
flag=1;
break;
}
else if(key<a[mid])
{
high=mid-1;
}
else
low=mid+1;
}
if(flag==1)
printf("\n The number is found and its position is: %d")
else
printf("\n The number is not found");
getch();
}

21
SORTINGS:

 Definition: Sorting is a technique to rearrange the list of records(elements) either in ascending


or descending order, Sorting is performed according to some key value of each record.
Categories of Sorting:
The sorting can be divided into two categories. These are:
 Internal Sorting
 External Sorting

 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

Algorithm for finding minimum element in the list.


SMALLEST (ARR, K, N, Loc)
Step 1: [INITIALIZE] SET Min = ARR[K]
Step 2: [INITIALIZE] SET Loc = K
Step 3: Repeat for J = K+1 to N
IF Min > ARR[J]
SET Min = ARR[J]
SET Loc = J
[END OF IF]
[END OF LOOP]
Step 4: RETURN Loc

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;

printf ("Enter number of elements\n");


scanf("%d", &n);

printf("Enter %d integers\n", n);

for (i = 0; i < n; i++)


scanf("%d", &a[i]);

for (i = 0; i < (n - 1); i++) // finding minimum element (n-1) times


{
position = i;

for (j = i + 1; j < n; j++)

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 is also called as Exchange Sort


 In Bubble Sort, each element is compared with its adjacent element
a) If he first element is larger than the second element then the position of the elements are
interchanged.
b) Otherwise, the position of the elements are not changed.
c) The same procedure is repeated until no more elements are left for comparison.
 After the 1st pass the largest element is placed
at (N-1)th location. Given a list of n elements,
the bubble sort requires up to n – 1 passes to
sort the data.
Example 1:
 We take an unsorted array for our example.

 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

Time Complexities All the Searching & Sorting Techniques:

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:

1. Single linked list


2. Double linked list
3. Circular linked list

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:

**** MAIN MENU


**** 1:CREATE
2:DISPLAY
3:EXIT

Enter Your Choice:1

Enter total no of Elements:7

Enter elements:10 20 30 40 50 60 70

**** MAIN MENU


**** 1:CREATE
2:DISPLAY
3:EXIT

Enter Your Choice:2


10-->20-->30-->40-->50-->60-->70-->NULL
**** MAIN MENU
**** 1:CREATE
2:DISPLAY
3:EXIT

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:

**** MAIN MENU


**** 1:CREATE
2:INSERT
3:DISPLAY
4:EXIT

Enter Your Choice:1

Enter total no of
Elements:5 Enter
elements:10 20 30 40 50
**** MAIN MENU
**** 1:CREATE
2:INSERT
3:DISPLAY
4:EXIT

Enter Your Choice:3


10-->20-->30-->40-->50-->NULL
**** MAIN MENU
**** 1:CREATE
2:INSERT
3:DISPLAY
4:EXIT
Enter our Choice: 2
Enter an Element:
60 INSERT AS
1:AT THE FRONT
2:AT THE END
3:AT ANY OTHER POSITION
Enter Your Choice:1
**** MAIN MENU
**** 1:CREATE
2:INSERT
3:DISPLAY
4:EXIT

Enter Your Choice:3


60-->10-->20-->30-->40-->50-->NULL
**** 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

**** MAIN MENU


**** 1:CREATE
2:INSERT
3:DISPLAY
4:EXIT
Enter Your
Choice:2 Enter an
Element:80
INSERT AS
1:AT THE FRONT
2:AT THE END
3:AT ANY OTHER POSITION
Enter Your Choice:3

Enter the Position to Insert:5

**** MAIN MENU


**** 1:CREATE
2:INSERT
3:DISPLAY
4:EXIT

Enter Your Choice:3


60-->10-->20-->30-->80-->40-->50-->70-->NULL
**** MAIN MENU
**** 1:CREATE
2:INSERT
3:DISPLAY
4:EXIT

Enter Your Choice:4

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:

**** MAIN MENU


**** 1:CREATE
2:DELETE
3:DISPLAY
4:EXIT

Enter Your Choice:1

MAIN MENU ****


1:CREATE
10
2:DELETE
3:DISPLAY
4:EXIT
Enter Your
Choice:2
DELETE AS
1:AT THE FRONT
2:AT THE END
3:AT ANY OTHER POSITION
Enter Your Choice:2

Deleted Element is: 80


**** MAIN MENU
**** 1:CREATE
2:DELETE
3:DISPLAY
4:EXIT

Enter Your Choice:3


20-->30-->40-->50-->60-->70-->NULL
**** MAIN MENU
**** 1:CREATE
2:DELETE
3:DISPLAY
4:EXIT
Enter Your
Choice:2
DELETE AS
1:AT THE FRONT
2:AT THE END
3:AT ANY OTHER POSITION
Enter Your Choice:3
Enter the Position of Deletion:4
Deleted Element is: 50
**** MAIN MENU ****
1:CREATE
2:DELETE
3:DISPLAY
4:EXIT

Enter Your Choice:3


20-->30-->40-->60-->70-->NULL
**** MAIN MENU
**** 1:CREATE
2:DELETE
3:DISPLAY
4:EXIT

Enter Your Choice:4

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.

Q)What are the Applications of Single Linked List?

Applications of Single Linked List: Linked list is used in a wide variety of applications suchas:

1. Polynomial Manipulation representation


2. Memory management
3. Mailing list
4. LISP
5. Linked allocation of files
6. Virtual Memory
7. Support for other data structures
1. Polynomial Manipulation representation: A polynomial is a collection of different terms, each
comprising coefficients, and exponents. It can be represented using a linked list. This representation
makes polynomial manipulation efficient.
2. Memory Management: Memory management is one of the operating system's key features. It decides
how to allocate and reclaim storage for processes running on the system. We can use a linked list to keep
track of portions of memory available for allocation.
3. Mailing List: Linked lists have their use in email applications. Since it is difficult to predict multiple
lists, maybe a mailer builds a linked list of addresses before sending a message.
4. LISP: LISP is an acronym for LIST processor, an important programming language in artificial
intelligence. This language extensively uses linked lists in performing symbolic processing.
5. Linked allocation of files: A file of large size may not be stored in one place on a disk. Sothere must be
some mechanism to link all the scattered parts of the file together. The use of a linked list allows an
efficient file allocation method in which each block of a file contains a pointer to the file's text block. But
this method is good only for sequential access.
6. Virtual Memory: An interesting application of linked lists is found in the way systems support virtual
memory.
7. Support for other data structures: Some other data structures like stacks, queues, hash tables, graphs can
be implemented using a linked list.

Q)What are the Advantages and disadvantages of Single Linked List?

Advantages of Singly Linked List: There are some advantages of singly Linked List

1. It is very easier for the accessibility of a node in the forward direction.


2. The insertion and deletion of a node are very easy.
3. The Requirement will less memory when compared to doubly, circular or doubly circular linked
list.
4. The Singly linked list is the very easy data structure to implement.
5. During the execution, we can allocate or de allocates memory easily.
6. Insertion and deletion of elements don’t need the movement of all the elements whencompared

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>

void insert beginning(int);

struct node

int data;

struct node *next;

struct node *prev;

};

struct node *head;

void main ()

int choice,item;

do

printf("\nEnter the item which you want to insert?\n");

scanf("%d",&item);

insertbeginning(item);

printf("\nPress 0 to insert more ?\n");

scanf("%d",&choice);

}while(choice == 0);

void insertbeginning(int item)

struct node *ptr = (struct node *)malloc(sizeof(struct node));


15
if(ptr == NULL)

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

Enter the item which you want to insert?


12

16
Press 0 to insert more ?
0

Enter the item which you want to insert?


23

Press 0 to insert more ?


2

Output

Enter the item which you want to insert?


12

Press 0 to insert more ?


2

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

looks like as follows:

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;

struct node *next;

};

struct node *head;

void main ()

{
19
int choice,item;

do

printf("\nEnter the item which you want to insert?\n");

scanf("%d",&item);

beg_insert(item);

printf("\nPress 0 to insert more ?\n");

scanf("%d",&choice);

}while(choice == 0);

void beg_insert(int item)

struct node *ptr = (struct node *)malloc(sizeof(struct node));

struct node *temp;

if(ptr == NULL)

printf("\nOVERFLOW");

else

ptr -> data = item;

if(head == NULL)

head = ptr;

ptr -> next = head;

}
20
else

temp = head;

while(temp->next != head)

temp = temp->next;

ptr->next = head;

temp -> next = ptr;

head = ptr;

printf("\nNode Inserted\n");

Output

Enter the item which you want to insert?


12

Node Inserted

Press 0 to insert more ?


0

Enter the item which you want to insert?


90

Node Inserted

Press 0 to insert more ?


2

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 .

Advantages of Circular Linked List:


1. No requirement for a NULL assignment in the code. The circular list never points to a NULL
pointer unless fully de allocated.
2. Circular linked lists are advantageous for end operations since beginning and end coincide.
Algorithms such as the Round Robin scheduling can neatly eliminate processes which are queued
in a circular fashion without encountering dangling or NULL-referential pointers.
3. Circular linked list also performs all regular functions of a singly linked list. In fact, circulardoubly
linked lists discussed below can even eliminate the need for a full-length traversal to locate an
element. That element would at most only be exactly opposite to the start, completing just half the
linked list.
Disadvantages of Circular Linked List:
1. The disadvantages in using a circular linked list are below:
2. Circular lists are complex as compared to singly linked lists.
3. Reverse of circular list is a complex as compared to singly or doubly lists.
4. If not handled carefully, then the code may go in an infinite loop.
5. Harder to find the end of the list and loop control.
6. Inserting at Start, we have to traverse the complete list to find the last node.(Implementation
Perspective)

Q) Applications of linked lists?


A linked list is a linear data structure, in which the elements are not stored at contiguous memory locations.
The elements in a linked list are linked using pointers as shown in the below image:

22
Linked-List

Applications of linked list in computer science:

1. Implementation of stacks and queues


2. Implementation of graphs: Adjacency list representation of graphs is the most popular which uses a linked
list to store adjacent vertices.
3. Dynamic memory allocation: We use a linked list of free blocks.
4. Maintaining a directory of names
5. Performing arithmetic operations on long integers
6. Manipulation of polynomials by storing constants in the node of the linked list
7. Representing sparse matrices

Applications of linked list in the real world:

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

Q1)What is STACK? Explain about STACK operations?


 Stack is a linear data structure to which insertions and deletions are done from one end
called top. It follows Last In First Out(LIFO) technique. The technique operation for
inserting an element into the stack is referred as PUSH, and for deleting an element is
referred as POP.
 Inserting an element into the stack when it is full leads to stack overflow. Deleting an
element from stack when it is empty leads to stack underflow.
 A stack may be referred as linear data structure or static data structure or homogeneous
data structure.
 Stack is used in many computer applications. It is used in system software like operating
systems, compilers. More over a stack may be implemented either using arrays or using
linked list.
PROPERTIES OF STACK...
There are following important properties of stack-
(i)All insertions and deletions can occur only at the top of stack.
(ii) The elements that are removed from stack in reverse order in which
they were inserted.
(iii) Only one element can be pushed or popped from the stack at a time.
(iv) It works in last-in-first-out or LIFO manner
Standard Stack Operations:
The following are some common operations implemented on the stack:
 push(): When we insert an element in a stack then the operation is known as a push. If the
stack is full then the overflow condition occurs.
 pop(): When we delete an element from the stack, the operation is known as a pop. If the
stack is empty means that no element exists in the stack, this state is known as an
underflow state.
Peek (or Top):
The peek operation, also known as top, allows you to view the element at the top of the
stack without removing it. This is useful for inspecting the current top element.

Peeking doesn't alter the stack's structure; it only provides information about the top
element.

 isEmpty(): It determines whether the stack is empty or not.


 isFull(): It determines whether the stack is full or not.'
 peek(): It returns the element at the given position.
 count(): It returns the total number of elements available in a stack.
 change(): It changes the element at the given position.
 display(): It prints all the elements available in the stack.
Structure of STACK: Consider the stack with size is 5. Then the STACK is created as EMPTY
STACK as given below:

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.

Example: C program to implement Stack operations using Arrays.


#include <stdio.h>
int stack[100],i,j,choice=0,n,top=-1;
void push();
void pop();
void show();
void main ()
{
printf("Enter the number of elements in the stack ");
scanf("%d",&n);
printf("*********Stack operations using array*********");
printf("\n \n");
while(choice != 4)
{
printf("Chose 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:
{
show(); break;
}
case 4:
{
printf("Exiting ");
break;
}
default:
{
printf("Please Enter valid choice ");
}
}
}
}

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");
}
}

Q)2)Explain the Representation of STACK using LINKED LIST

 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;
}
}
}

Q)3)What are the applications of STACK?


Applications of stacks:
Following are some of the important applications of a Stack data structure:
1. Stacks can be used for expression evaluation.
2. Stacks can be used to check parenthesis matching in an expression.
3. Stacks can be used for Conversion from one form of expression to another.
4. Stacks can be used for Memory Management.
5. Stack data structures are used in backtracking problems.
1. Expression Evaluation: Stack data structure is used for evaluating the given expression. For
example, consider the following expression
5 * ( 6 + 2 ) - 12 / 4
Since parenthesis has the highest precedence among the arithmetic operators, ( 6 +2 ) = 8 will be
evaluated first. Now, the expression becomes
5 * 8 - 12 / 4
* and / have equal precedence and their associativity is from left-to-right. So, start evaluating the
expression from left-to-right.
5 * 8 = 40 and 12 / 4 = 3
Now, the expression becomes
40 - 3
And the value returned after the subtraction operation is 37.
2. Parenthesis Matching: Given an expression, you have to find if the parenthesis is either
correctly matched or not. For example, consider the expression ( a + b ) * ( c + d ).
In the above expression, the opening and closing of the parenthesis are given properly and hence
it is said to be a correctly matched parenthesis expression. Whereas, the expression, (a + b * [c +
d ) is not a valid expression as the parenthesis are incorrectly given.
3. Expression Conversion: Converting one form of expressions to another is one of the
important applications of stacks.

 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.

Q)4)What are the applications of stacks in Expression Evaluation?


A postfix expression can be evaluated using the Stack data structure. To evaluate a postfix
expression using Stack data structure we can use the following steps...
 Read all the symbols one by one from left to right in the given Postfix Expression
 If the reading symbol is operand, then push it on to the Stack.
 If the reading symbol is operator (+ , - , * , / etc.,), then perform TWO pop operations
and store the two popped oparands in two different variables (operand1 and operand2).
Then perform reading symbol operation using operand1 and operand2 and push result
back on to the Stack.
 Finally! perform a pop operation and display the popped value as final result.

Example: Consider the following Expression...

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;
}

Q)5)Explain the Backtracking in stacks?


The backtracking algorithm is a problem-solving approach that tries out
all the possible solutions and chooses the best or desired ones. Generally,
it is used to solve problems that have multiple solutions. The term
13
backtracking suggests that for a given problem, if the current solution is
not suitable, eliminate it and then backtrack to try other solutions.

When do we use backtracking algorithm?

Backtracking algorithm can be used for the following problems −


 The problem has multiple solutions or requires finding all possible
solutions.
 When the given problem can be broken down into smaller sub
problems that are similar to the original problem.
 If the problem has some constraints or rules that must be satisfied by
the solution

How does backtracking algorithm work?


The backtracking algorithm explores various paths to find a sequence path that takes
us to the solution. Along these paths, it establishes some small checkpoints from
where the problem can backtrack if no feasible solution is found. This process
continues until the best solution is found.

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.

When backtracking algorithm reaches the end of the solution, it checks


whether this path is a solution or not. If it is the solution path, it returns
that otherwise, it backtracks to one step behind in order to find a 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!)).

Types of Backtracking Problem


The backtracking algorithm is applied to some specific types of
problems. They are as follows −

 Decision problem − It is used to find a feasible solution of the


problem.
 Optimization problem − It is used to find the best solution that can
be applied.
 Enumeration problem− It is used to find the set of all feasible
solutions of the problem.

Examples of Backtracking Algorithm


The following list shows examples of Backtracking Algorithm −

 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

Q)6)Explain the Reversing a LINKED LIST using STACK


In this problem we are given a singly linked list and we have to reverse it using a stack.
Input:

Output:

Now, the main question is how to use a stack to reverse a


linked list?We will look for that under Approach section.

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

Q1)What is Queue Data Structure? Properties of Queue? Explain it types?


 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’.
 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.
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 -

3. Deque: A deque is also known as a double-ended queue. Double Ended


Queue is also a Queue data structure in which the insertion and deletion
operations are performed at both the ends (front and rear). That means, we can
insert at both front and rear positions and can delete from both front and rear
positions.
Structure of the DeQue:

Q2) What is Queue Data Structure? And explain Queue


operations(or)Queue using arrays?

 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:

Operations of Queue: The basic operations of QUEUE are given below:

 Enqueue: The enqueue operation is used to insert the element at the


rear end of thequeue.
 Dequeue: The dequeue operation performs the deletion from the front-end of
the queue.
 Peek: This is the third operation that returns the element, which is pointed
by the frontpointer in the queue but does not delete it.
 Queue overflow (isfull): When the Queue is completely full, then it shows
the overflowcondition.
 Queue underflow (isempty): When the Queue is empty, i.e., no
elements are in theQueue then it throws the underflow condition.
Example: Consider the Queue with size is 5, then the created EMPTY QUEUE is as
follows:

Enqueue operation: The enqueue operation is used to insert the element at


the rear end ofthe queue.
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..

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.

Example: C program for implementation all operations on Queue


using Array

#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;

if (front == -1 || front > rear)


{
printf("\nUNDERFLOW\n");
return;

}
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:

 If we implement the queue using an array, we need to specify the array


size at thebeginning (at compile time).
 We can't change the size of an array at runtime. So, the queue will only work
for a fixednumber of elements.
Solution:
 We can implement the queue data structure using the linked list. In the linked
list, we canchange its size at runtime.
Queue using Linked List:
 To implement Queue using single linked list concept, all the single linked list
operationsperform based on Queue operations of FIFO (First In First Out)
technique.

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.

Example: C program to implement all operations on queue using linked


list.
#include<stdio.h>
#include<stdlib.h>
struct node
{
int data;
struct node *next;

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;
}
}
}

Q4)What are the Applications of Queue?


Applications of Queue:

There are various applications of queues as shown below.

 CPU scheduling- to keep track of processes for the CPU


 Handling website traffic - by implementing a virtual HTTP request queue
 Printer Spooling - to store print jobs
 In routers - to control how network packets are transmitted or discarded
 Traffic management - traffic signals use queues to manage intersections

Q5)Explain about 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

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.

Operations of Circular Queue:


 Front: It is used to get the front element from the Queue.
 Rear: It is used to get the rear element from the Queue.
 enQueue(value): This function is used to insert the new value in the
Queue. The new element is always inserted from the rear end.
 deQueue(): This function deletes an element from the Queue. The deletion
in a Queue always takes place from the front end.
Example: Consider the CQueue with size is 6, then the created EMPTY CQUEUE is as
follows:

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..

From the above step we can say that,


In CIRCULAR QUEUE we can again insert new values at the deleted positions.

Q6)Explain about Applications of Queues in breadth-first search?

Breadth-first Search:

Breadth First Search Algorithm


This search operation traverses all the nodes at a single level/hierarchy before
moving on to the next level of nodes. BFS algorithm starts at the first node and
traverses all adjacent nodes before proceeding to the next level repeating the same
process.

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.

Here's the algorithm for the same:

Step 1: Set the status=1(ready state) for each node in G.

Step 2: Insert the first node A and set its status = 2(waiting state).

Step 3: Now, repeat steps 4 and 5 until the queue is empty

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

BFS Algorithm Example

Let’s consider the following graph to understand a BFS example:

A––B
| |
C––D

We want to perform a breadth first search (BFS) traversal from vertex


A to visit all the vertices.

Step 1:

 Enqueue vertex A into the queue.


 Mark A as visited.
 Queue: [A]
 Visited: {A}
Step 2:
16
 Dequeue A from the queue and process it (e.g., print or perform operations).
 Enqueue its neighbours, B and C, into the queue (as they have yet to be
visited).
 Mark B and C as visited.
 Queue: [B, C]
 Visited: {A, B, C}
Step 3:

 Dequeue B from the queue and process it.


 Enqueue its neighbour D into the queue (as it is not visited yet).
 Mark D as visited.
 Queue: [C, D]
 Visited: {A, B, C, D}
Step 4:

 Dequeue C from the queue and process it.


 There are no unvisited neighbours of C, so no vertices are enqueued.
 Queue: [D]
 Visited: {A, B, C, D}
Step 5:

 Dequeue D from the queue and process it.


 There are no unvisited neighbours of D, so no vertices are enqueued.
 Queue: []
 Visited: {A, B, C, D}
The BFS algorithm has now traversed all vertices reachable from the
starting vertex A in a breadth-first manner. The order of traversal is A,
B, C, and D.

Q7)Explain about application of queue in Scheduling?

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.

Algorithm for the said function:

Start traversing the pages.

If a frame holds fewer pages than its full allocation capacity-

 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

If the current page is present in the set, do nothing.

Else

 Remove the first page from the queue.


 Replace it with the current page in the string and store the current
page in the queue.
 Increment page faults.

Return page faults.

This First Come First Serve (FCFS) method offers both non-
preemptive and pre-emptive scheduling algorithms.

18
FCFS CPU Scheduling

Q8)Another application of queue in Printer Spooling?

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)?

A deque is also known as a double-ended queue. Double Ended Queue is also a


Queue data structure in which the insertion and deletion operations are performed
at both the ends (front and rear). That means, we can insert at both front and
rear positions and can delete from both front and rear positions.
Structure of the DeQue:

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

Inserting Using Rear:


Step1: Inserting ‘10’ element into DeQue, then the Deque is as follows..

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..

Removing values using Front:


Step1: Removing ‘10’ element from the 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:

Inserting using Front:


Step1: inserting ‘60’ element using Front end is as follows..

Step2: inserting ‘70’ element using Front end is as follows..

Deletion from Rear:


Step1: Deleting ‘50’ element from Rear end is as follows..

22
Step2: Deleting ‘40’ and ‘30’ elements from Rear end is as follows..

Q)2)Explain Applications of Deques?


 It is used in job scheduling algorithms.
 It supports both stack and queue operations.
 The clockwise and anti-clockwise rotation operations in deque are performed
in O(1) time which is helpful in many problems.
Real-time Application of Deque:
 In a web browser’s history, recently visited URLs are added to the front of
the deque and the URL at the back of the deque is removed after some
specified number of operations of insertions at the front.
 Storing a software application’s list of undo operations.
 In graph traversal algorithms such as breadth-first search (BFS). BFS uses a
deque to store nodes and performs operations such as adding or removing
nodes from both ends of the deque.
 In task management systems to manage the order and priority of incoming
tasks. Tasks can be added to the front or back of the deque depending on
their priority or deadline.
 In queueing systems to manage the order of incoming requests. Requests
can be added to the front or back of the deque depending on their priority or
arrival time.
 In caching systems to cache frequently accessed data. Deques can be used
to store cached data and efficiently support operations such as adding or
removing data from both ends of the deque.
Advantages of Deque:
 You are able to add and remove items from the both front and back of the
queue.
 Deques are faster in adding and removing the elements to the end or
beginning.
 The clockwise and anti-clockwise rotation operations are faster in a deque.
 Dynamic Size: Deques can grow or shrink dynamically.
 Efficient Operations: Deques provide efficient O(1) time complexity for
inserting and removing elements from both ends.
 Versatile: Deques can be used as stacks (LIFO) or queues (FIFO), or as a
combination of both.

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.

Terminologies In Tree Data 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.

{K, L, M, N, O, P, G} are the leaf nodes of the tree.

 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}

 Descendant: A node x is a descendant of another node y if and only if y is an ancestor of y.

 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.

 Subtree: Any node of the tree along with its descendant.

Types of Tree Data Structure:

 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.

Applications of Tree Data Structure:

 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.

Introduction to Binary Search Tree

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.

Properties of Binary Search Tree:


 The left subtree of a node contains only nodes with keys lesser than the node’s key.
 The right subtree of a node contains only nodes with keys greater than the node’s key.
 This means everything to the left of the root is less than the value of the root and everything to the right of
the root is greater than the value of the root. Due to this performing, a binary search is very easy.
 The left and right subtree each must also be a binary search tree.
 There must be no duplicate nodes (BST may have duplicate values with different handling approaches)

Handling duplicate values in the Binary Search Tree:


 We must follow a consistent process throughout i.e. either store duplicate value at the left or store the
duplicate value at the right of the root, but be consistent with your approach.

Basic Operations on Binary Search Tree:

1. Searching a node in BST:


Searching in BST means to locate a specific node in the data structure. In Binary search tree, searching a node
is easy because of its a specific order. The steps of searching a node in Binary Search tree are listed as follows

1. First, compare the element to be searched with the root element of the tree.
 If root is matched with the target element, then return the node’s location.
 If it is not matched, then check whether the item is less than the root element, if it is smaller than the
root element, then move to the left subtree.
 If it is larger than the root element, then move to the right subtree.
2. Repeat the above procedure recursively until the match is found.
3. If the element is not found or not present in the tree, then return NULL.
Now, let’s understand the searching in binary tree using an example:
Below is given a BST and we have to search for element 6.

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

// Given Node Structure


struct node {
int key;
struct node *left, *right;
};

// Function to create a new BST node


struct node* newNode(int item)
{
struct node* temp
= (struct node*)malloc(
sizeof(struct node));
temp->key = item;
temp->left = temp->right = NULL;
return temp;
}

// Function to insert a new node with


// given key in BST
5
struct node* insert(struct node* node, int key)
{
// If the tree is empty, return a new node
if (node == NULL)
return newNode(key);

// Otherwise, recur down the tree


if (key < node->key) {
node->left = insert(node->left, key);
}
else if (key > node->key) {
node->right = insert(node->right, key);
}

// Return the node pointer


return node;
}

Delete a Node of BST:


It is used to delete a node with specific key from the BST and return the new BST.

Different scenarios for deleting the node:

Node to be deleted is the leaf node :


Its simple you can just null it out.

Node to be deleted has one child :


You can just replace the node with the child node.

Node to be deleted has two child :


Here we have to delete the node is such a way, that the resulting tree follows the properties of a BST. The
trick is to find the inorder successor of the node. Copy contents of the inorder successor to the node, and delete
the inorder successor.
6
Take Care of following things while deleting a node of a BST:
1. Need to figure out what will be the replacement of the node to be deleted.
2. Want minimal disruption to the existing tree structure
3. Can take the replacement node from the deleted nodes left or right subtree.
4. If taking if from the left subtree, we have to take the largest value in the left subtree.
5. If taking if from the right subtree, we have to take the smallest value in the right subtree.

Code:

Below is the implementation of the deletion in BST:


C++CJavaPython
// C program to delete
// a node of BST
// Given Node node
struct node {
int key;
struct node *left, *right;
};

// Function to create a new BST node


struct node* newNode(int item)
{
struct node* temp
= (struct node*)malloc(
sizeof(struct node));
temp->key = item;
temp->left = temp->right = NULL;
return temp;
}

// Function to insert a new node with


// given key in BST
struct node* insert(struct node* node, int key)
{
// If the tree is empty, return a new node
if (node == NULL)
return newNode(key);

// Otherwise, recur down the tree


7
if (key < node->key)
{
node->left = insert(node->left, key);
}
else if (key > node->key)
{
node->right = insert(node->right, key);
}

// Return the node pointer


return node;
}

// Function that returns the node with minimum


// key value found in that tree
struct node* minValueNode(struct node* node)
{
struct node* current = node;

// Loop down to find the leftmost leaf


while (current && current->left != NULL)
current = current->left;

return current;
}

// Function that deletes the key and


// returns the new root
struct node* deleteNode(struct node* root,
int key)
{
// base Case
if (root == NULL)
return root;

// If the key to be deleted is


// smaller than the root's key,
// then it lies in left subtree
if (key < root->key) {
root->left
= deleteNode(root->left, key);
}

// If the key to be deleted is


// greater than the root's key,
// then it lies in right subtree
else if (key > root->key) {

root->right

8
= deleteNode(root->right, key);
}

// If key is same as root's key,


// then this is the node
// to be deleted
else {

// Node with only one child


// or no child
if (root->left == NULL) {
struct node* temp = root->right;
free(root);
return temp;
}
else if (root->right == NULL) {
struct node* temp = root->left;
free(root);
return temp;
}

// Node with two children:


// Get the inorder successor(smallest
// in the right subtree)
struct node* temp = minValueNode(root->right);

// Copy the inorder successor's


// content to this node
root->key = temp->key;

// Delete the inorder successor


root->right
= deleteNode(root->right, temp->key);
}
return root;
}

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).

Common hash functions include:

 Division Method: Key % Hash Table Size


 Multiplication Method: (Key * Constant) % Hash Table Size
 Universal Hashing: A family of hash functions designed to minimize collisions

What is a Hash Collision?

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.

Causes of Hash Collisions:

 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.

Collision Resolution Techniques

There are two types of collision resolution techniques:


1. Open Addressing:
 Linear Probing: Search for an empty slot sequentially
 Quadratic Probing: Search for an empty slot using a quadratic function

2. Closed Addressing:
 Chaining: Store colliding keys in a linked list or binary search tree at each index
 Cuckoo Hashing: Use multiple hash functions to distribute keys

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.

Need for Hash data structure


The amount of data on the internet is growing exponentially every day, making it difficult to store it all
effectively. In day-to-day programming, this amount of data might not be that big, but still, it needs to be stored,
accessed, and processed easily and efficiently. A very common data structure that is used for such a purpose is
the Array data structure.
Now the question arises if Array was already there, what was the need for a new data structure! The answer to
this is in the word “efficiency“. Though storing in Array takes O(1) time, searching in it takes at least O(log
n) time. This time appears to be small, but for a large data set, it can cause a lot of problems and this, in turn,
makes the Array data structure inefficient.
So now we are looking for a data structure that can store the data and search in it in constant time, i.e.
in O(1) time. This is how Hashing data structure came into play. With the introduction of the Hash data structure,
it is now possible to easily store data in constant time and retrieve them in constant time as well.

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.

Collision Resolution Techniques


There are two types of collision resolution techniques.
 Separate chaining (open hashing)
 Open addressing (closed hashing)

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.

2.a) Linear Probing


In linear probing, the hash table is searched sequentially that starts from the original location of the
hash. If in case the location that we get is already occupied, then we check for the next location.
Algorithm:
1. Calculate the hash key. i.e. key = data % size
2. Check, if hashTable[key] is empty
 store the value directly by hashTable[key] = data
3. If the hash index already has some value then

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.

2.b) Quadratic Probing


Quadratic probing is an open addressing scheme in computer programming for resolving hash
collisions in hash tables. Quadratic probing operates by taking the original hash index and adding successive
values of an arbitrary quadratic polynomial until an open slot is found.
An example sequence using quadratic probing is:

H + 12, H + 22, H + 32, H + 42…………………. H + k2

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

 Step 1: Create a table of size 7.

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,

 Now, cell 5 is not occupied so we will place 50 in slot 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.

This combination of hash functions is of the form

h(k, i) = (h1(k) + i * h2(k)) % n

where

 i is a non-negative integer that indicates a collision number,

 k = element/key which is being hashed

 n = hash table size.

Complexity of the Double hashing algorithm:

Time complexity: O(n)

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

o 27 % 7 = 6, location 6 is empty so insert 27 into 6 slot.

21
Step 2: Insert 43
43 % 7 = 1, location 1 is empty so insert 43 into 1 slot.

 Step 3: Insert 692

o 692 % 7 = 6, but location 6 is already being occupied and this is a collision

o So we need to resolve this collision using double hashing.

hnew = [h1(692) + i * (h2(692)] % 7


= [6 + 1 * (1 + 692 % 5)] % 7
=9%7
=2

Now, as 2 is an empty slot,


so we can insert 692 into 2nd slot.

22
 Step 4: Insert 72

o 72 % 7 = 2, but location 2 is already being occupied and this is a collision.

o So we need to resolve this collision using double hashing.

hnew = [h1(72) + i * (h2(72)] % 7


= [2 + 1 * (1 + 72 % 5)] % 7
=5%7
= 5,
Now, as 5 is an empty slot,
so we can insert 72 into 5th slot.

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.

Linking File name and path together:

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

You might also like