Download as pdf or txt
Download as pdf or txt
You are on page 1of 68

MEENAKSHI SUNDARARAJAN ENGINEERING COLLEGE

Kodambakkam, Chennai-600 024

DEPARTMENT OF ARTIFICIAL INTELLIGENCE AND DATA


SCIENCE

AD3271 DATA STRUCTURES DESIGN LABORATORY


LAB MANUAL
Regulation 2021

Year / Sem : I / II
LIST OF EXPERIMENTS

EXPT NAME OF THE PAGE


DATE MARKS SIGN
NO. EXPERIMENT NO.

Implement simple ADTs as


1.
Python classes

Implement recursive algorithms


2.
in Python

Implement List ADT using


3.
Python arrays

Linked list implementations of


4.
List

Implementation of Stack and


5.
Queue ADTs

Application of List, Stack and


6.
Queue

Implementation of searching
7. and sorting algorithms

Implementation of Hash tables


8.

Tree representation and Tree


9.
Traversal Algorithms

Implementation of Binary
10.
Search Trees

11. Implementation of Heaps

Graph representation and Graph


12.
Traversal Algorithms

Implementation of single source


13.
shortest path algorithm

Implementation of minimum
14.
spanning tree algorithms
Ex. No:1 Implement simple ADTs as Python classes

Aim:

To Implement simple ADTs as Python classes using Stack, Queue, List using python.

Theory to practical mapping:

CO1: Explain abstract data types.

Theory:

An ADT is a programmer defined data type that is more abstract than the data
types provided by the programming language. ADT's provide a representation for
data entities in the problem domain, e.g., Customer, Vehicle, Parts List, Address
Book.

Algorithm:

Step 1: Create a Stack[ ],Queue[],List[] with MAX size as your wish.


Step 2: Write function for all the basic operations of stack,Queue,List - PUSH(), POP() and
DISPLAY(),append(),Extend().
Step 3: Close the program

Coding :

Stack:
stack = []
stack.append(a')
stack.append('b')
stack.append('c')
print('Initial stack')
print(stack)
print('\nElements poped from stack:')
print(stack.pop()) print(stack.pop())
print(stack.pop())
print('\nStack after elements are poped:')
print(stack)

Queue:
queue = []
queue.append('a')
queue.append('b')
queue.append('c')
print("Initial queue")
print(queue)
print("\nElements dequeued from queue")
print(queue.pop(0))
print(queue.pop(0))
print(queue.pop(0))
print("\nQueue after removing elements")
print(queue)

List:
List = [1,2,3,4]
print("Initial List: ")
print(List)
List.extend([8, 'Geeks', 'Always'])
print("\nList after performing Extend Operation: ")
print(List)

Output:

Stack:
Initial stack
['a', 'b', 'c']
Elements poped from
stack: c b a
Stack after elements are poped: []

Queue:
['a', 'b', 'c']
Elements dequeued from queue
a
b
c
Queue after removing elements: []

List:

Initial List:
[1, 2, 3, 4]
List after performing Extend Operation: [1, 2, 3, 4, 8, 'Geeks', 'Always']
Result:
Thus the Implementation of simple ADTs as Python classes was executed successfully.

Real Time applications:

Some Applications of a stack are:


• Undo/Redo button/operation in word processors.
• Syntaxes in languages are parsed using stacks.
• It is used in many virtual machines like JVM.
• Forward-backward surfing in the browser.
• History of visited websites.
• Message logs and all messages you get are arranged in a stack.
• Call logs, E-mails, Google photos’ any gallery, YouTube downloads, Notifications (
latest appears first ).

Some Applications of a queue are:


• Operating System uses queues for job scheduling.
• To handle congestion in the networking queue can be used.
• Data packets in communication are arranged in queue format.
• Sending an e-mail, it will be queued.
• Server while responding to request
• Uploading and downloading photos, first kept for uploading/downloading will be
completed first (Not if there is threading)

Some Applications of a list are:


• Social Media Applications.
• Music Streaming Platforms.

Viva:

• What is ADT?
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).

• What is the concept of ADT?


An Abstract Data Type (ADT) is a programming concept that defines a high-
level view of a data structure, without specifying the implementation details.

• What are the three types of ADT?


data types: list, queue, stack.
• What is the difference between ADT and class?
One way of thinking of a class is as an abstract data type plus inheritance and
polymorphism. An abstract data type (ADT) is a mathematical abstraction of a
real world thing and can be implemented in a concrete data type in different
languages.

• What are the applications of ADT?


• 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.
Ex. No:2 Implement Recursive Algorithms in Python

Aim:

To Implement a recursive algorithm in Python using Fibonacci Series.

Theory to practical mapping:

CO1: Explain abstract data types.

Theory:

A recursive algorithm is an algorithm which calls itself with a smaller problem. It is an


alternative to iteration. For some problems a recursive algorithm can be much easier to develop,
code, and comprehend.

Algorithm:

Step 1:Input the 'n' value until which the Fibonacci series has to be generated

Step 2:Initialize sum = 0, a = 0, b = 1 and count = 1

Step 3:while (count <= n)

Step 4:print sum

Step 5:Increment the count variable

Step 6:swap a and b

Step 7:sum = a + b

Step 8:while (count > n)

Step 9:End the algorithm

Step 10:Else

Step 11:Repeat from steps 4 to 7

Coding:

No = 10
num1, num2 = 0, 1
count = 0
if No <= 0:
print("Invalid Number")
elif No == 1:
print("Fibonacci sequence for limit of ",No,":")
print(num1)
else:
print("Fibonacci sequence:")
while count < No:
print(num1)
nth = num1 + num2
num1 = num2
num2 = nth
count += 1

Output:

Fibonacci sequence:
0
1
1
2
3
5
8
13
21
34

Result:
Thus the Implementation of recursive algorithms in Python using Fibonacci series was
executed successfully.
Real Time application:

• Recursive algorithms can be used for sorting and searching data structures such as
linked lists, binary trees, and graphs.
• They are also often used for string manipulation tasks such as checking if two strings
are anagrams or finding the longest common subsequence between two strings.
• Another common use case for recursion is traversing complex data structures such as
JSON objects or directory trees on file systems.
• Finally, they can also be used to generate fractals or create animation effects using
recursive rendering techniques.

Viva:

• What is Recursive?
The process in which a function calls itself directly or indirectly is called recursion.

• Why recursive algorithms?


It is an alternative to iteration. For some problems a recursive algorithm can be much
easier to develop, code, and comprehend.

• What is the advantage of recursive?


Recursion is considered a powerful tool for solving complex problems because it
allows breaking down large and intricate problems into smaller, more manageable sub
problems.

• What are limitations of recursion?


Performance: Recursive functions can be slower than iterative functions, especially
when dealing with large inputs. Each recursive call creates a new stack frame, which
requires additional memory and processing time. Readability: Recursive functions can
be harder to read and understand than iterative functions.

• How many types of recursive algorithms are there?


There are 2 types of recursion direct recursion and indirect recursion.
Ex. No:3 Implement List ADT using Python arrays

Aim:
To Implement List ADT using Python arrays

Theory to practical mapping:

CO2: Design, implement, and analyse linear data structures, such as lists,
queues, and stacks, according to the needs of different applications.

Theory:

• Abstract data types (ADTs) are important for large-scale


programming. They package data structures and operations on them,
hiding internal details.
• The simplest method to implement a List ADT is to use an array that is
a “linear list” or a “contiguous list” where elements are stored in
contiguous array positions.
• In array implementation, elements are stored in contiguous array
positions. An array is a viable choice for storing list elements when the
elements are sequential, because it is a commonly available data type
and in general algorithm development is easy.

Algorithm:

Step 1:Using define function initialise the list


Step 2:while loop to declare the elements until the condition is satisfied.
Step 3:using convert arr function to convert the elements to an array
Step 4:Stop the program.
Coding:

class node:
def __init__(self, data):
self.data=data
self.next=None
def add(data):
nn=node(0)
nn.data=data
nn.next=None
return nn def
printarray(a,n):
i=0
while(i<n):
print(a[i], end = " ")
i=i+1
def findlength(head):
cur=head
count=0
while(cur!=None):
count=count+1
cur=cur.next
return count
def convertarr(head):
len=findlength(head)
arr=[]
index=0 cur=head
while(cur!=None):
arr.append(cur.data)
cur=cur.next
printarray(arr, len)
head=node(0)
head=add(6)
head.next = add(4)
head.next.next = add(3)
head.next.next.next = add(4)
convertarr(head)
Output:
[6,4,3,4]
[6 4 3 4]

Result:
Thus the implementation of List in arrays was executed successfully.

Real Time application:

An array gets used for storing data for mathematical computations. Besides, it
helps in image processing, record management, and ordering boxes. Besides,
book pages are also examples of the application of data structures arrays.

Viva:

• How is a list ADT implementation using arrays?


The simplest method to implement a List ADT is to use an array that
is a“linear list” or a “contiguous list” where elements are stored in
contiguous array positions.

• What is the difference between array and list in ADT?


An array is a grouping of data elements of equivalent data type. A
linked list is a group of entities called a node. The node includes two
segments: data and address.

• What is arr function in Python?


import array as arr. The array(data type, value list) function takes two
parameters, the first being the data type of the value to be stored and
the second is the value list.

• What is ADT?
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).

• What is the concept of ADT?


An Abstract Data Type (ADT) is a programming concept that defines
a high-level view of a data structure, without specifying the
implementation details.
Ex.NO:4 Linked list implementations of List

Aim:

To Implement the Linked list implementations of List using python.

Theory to practical mapping:

CO2: Design, implement, and analyse linear data structures, such as lists, queues, and stacks,
according to the needs of different applications.

Theory:

• In the linked-list implementation, one pointer must be stored for every item in the list,
while the array stores only the items themselves.
• On the other hand, the space used for a linked list is always proportional to the number
of items in the list.

Algorithm:

Step 1:Create a list[ ] with MAX size as your wish.


Step 2:Write function for all the basic operations of list - create(), insert(), deletion(),
display().
Step 3:Using append() to extend the elements, removal() to delete the elements.
Step 4:Close the program.

Coding:

List = [1,2,3,4]
print("Initial List: ")
print(List)
List.extend([8, 'Geeks', 'Always'])
print("\nList after performing Extend Operation: ")
print(List)
List = []
print("Blank List: ")
print(List)
List = [10, 20, 14]
print("\nList of numbers: ")
print(List)
List = ["Geeks", "For", "Geeks"]
print("\nList Items: ")
print(List[0])
print(List[2])
Adding the elements: List = [1,2,3,4]
print("Initial List: ")
print(List)
List.insert(3, 12)
List.insert(0, 'Geeks')
print("\nList after performing Insert Operation: ")
print(List)
List = [1, 2, 3, 4, 5,
6, 7, 8, 9, 10,
11, 12] print("Intial
List: ") print(List)
List.remove(5)
List.remove(6)
print("\nList after Removal of two elements: ")
print(List)
for i in range(1, 5):
List.remove(i)
print("\nList after Removing a range of elements: ")
print(List)
List = [['Geeks', 'For'] , ['Geeks']]
print("\nMulti-Dimensional List: ")
print(List)

Output:

Initial blank List:


[]
List after Addition of Three elements:
[1, 2, 4]
List after Addition of elements from 1-3:
[1, 2, 4, 1, 2, 3]
>>>
===================== RESTART: Z:/New folder/queue 1.py
=====================
Initial List:
[1, 2, 3, 4]
List after performing Insert Operation:
['Geeks', 1, 2, 3, 12, 4]
>>>
===================== RESTART: Z:/New folder/queue 1.py
=====================
Intial List:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
List after Removal of two elements:
[1, 2, 3, 4, 7, 8, 9, 10, 11, 12]
List after Removing a range of elements:
[7, 8, 9, 10, 11, 12]

Result:

Thus the list was created,inserted,removed and extend the element was executed
successfully.

Real Time application:

• Music players: Linked lists are commonly used in music players to


create playlists and play songs either from the beginning or the end of
the list.
• Image viewers: Image viewers also use linked lists to enable users to
easily navigate between images.

Viva:

• What are the two ways to implement a linked list?


• Create a singly linked list and make the last node point to the first node.
• Create a doubly linked list and make the last node point to the first node and
the first node point to the last node.

• What are the three 3 types of linked list?


Singly Linked list. Doubly Linked list. Circular Linked list.

• What are the advantages of linked list?


dynamic size, efficient insertion and deletion, memory efficiency, easy
implementation of abstract data types, and more efficient sorting in some cases.
• What are two characteristics of linked lists?
• Effective insertion and deletion: Inserting or removing elements from a list's
centre may be done quickly and efficiently with linked lists.
• Memory efficiency: linked lists don't require contiguous memory allocation.
• Flexibility: Linked lists offer a lot of versatility.

• Can we join two linked list together?


Create a method, mergeLinkedList(), which will traverse both the LinkedLists,
merge them into a single LinkedList, and return the single LinkedList.
Ex.No:5 Implementation of Stack and Queue ADTs

Aim:

To Implementation of Stack and Queue ADTs.

Theory to practical mapping:

CO2: Design, implement, and analyse linear data structures, such as lists, queues, and stacks,
according to the needs of different applications.

Theory:

The most fundamental operations in the stack ADT include: push(), pop(), peek(),
isFull(), isEmpty(). These are all built-in operations to carry out data manipulation and to
check the status of the stack. Stack uses pointers that always point to the topmost element
within the stack, hence called as the top pointer.

Algorithm:

Step 1:Create a Stack[ ],Queue[] with MAX size as your wish.


Step 2:Write function for all the basic operations of stack - append(), POP().
Step 3:Close the program.

Coding:

Stack:

stack = []
stack.append('a')
stack.append('b')
stack.append('c')
print('Initial stack')
print(stack)
print('\nElements poped from stack:')
print(stack.pop())
print(stack.pop())
print(stack.pop())
print('\nStack after elements are poped:')
print(stack)
Queue:

queue = []
queue.append('a')
queue.append('b')
queue.append('c')
print("Initial queue")
print(queue)
print("\nElements dequeued from queue")
print(queue.pop(0))
print(queue.pop(0))
print(queue.pop(0))
print("\nQueue after removing elements")
print(queue)

Output:

Initial stack
['a', 'b', 'c']
Elements poped from
stack: c b a
Stack after elements are poped: []

Result:

Thus the program was executed successfully.

Real Time application:

Stacks are used in various algorithms, data manipulation procedures and system
architecture - like process scheduling in operating systems. Real-world examples include the
'undo' function in software applications following the 'LIFO' principle and a web browser's
back button function using stack to track visited sites.
Viva:

• What are the two main operations of stack?


Push, which adds an element to the collection, and. Pop, which removes the most
recently added element.

• What is a stack in ADT specification?


A stack is a linear data structure that only allows data to be accessed from the top.

• What is the difference between stack ADT and queue ADT?


The primary difference between Stack and Queue Data Structures is that Stack
follows LIFO while Queue follows FIFO data structure type.

• What is Stack Overflow?


If Stack is full and PUSH operation is performed it is not possible to insert or Push
thenew items into the stack. This situation is called Stack Overflow.

• What operations can be done on Queue?


The following operations can be performed on queue:
• Enqueue operation- inserts new element in rear of the list.
• Dequeue operation -deletes the front element from the list.
• Isempty() operation -checks whether queue is empty or not.
Ex.No:6a Application of List

Aim:

To implement list application using Polynomial Addition in python.

Theory to practical mapping:

CO2: Design, implement, and analyse linear data structures, such as lists, queues, and stacks,
according to the needs of different applications.

Theory:

Using a linked list, we can perform various operations on polynomials, such as adding,
subtracting, multiplying, and dividing them. Linked lists can also be used to perform arithmetic
operations on long integers.

Algorithm:

Step 1:Using the define function initial elements will be declared.


Step 2:for loop gives the output of sum of the elements.
Step 3:print[poly] statement have the sum of two polynomial elements.
Step 4:Close the program.

Coding:

def add(A, B, m, n):


size = max(m, n);
sum = [0 for i in range(size)]
for i in range(0, m, 1):
sum[i] = A[i]
for i in range(n):
sum[i] += B[i]
return sum
def printPoly(poly, n):
for i in range(n):
print(poly[i], end = "")
if (i != 0):
print("x^", i, end = "")
if (i != n - 1):
print(" + ", end = "")
if __name__ == '__main__':
A = [5, 0, 10, 6]
B = [1, 2, 4]
m = len(A)
n = len(B)
print("First polynomial is")
printPoly(A, m)
print("\n", end = "")
print("Second polynomial is")
printPoly(B, n)
print("\n", end = "")
sum = add(A, B, m, n)
size = max(m, n)
print("sum polynomial is")
printPoly(sum, size)

Output:

First polynomial is
5 + 0x^1 + 10x^2 + 6x^3
Second polynomial is
1 + 2x^1 + 4x^2
Sum polynomial is
6 + 2x^1 + 14x^2 + 6x^3

Result:

Thus the program was executed successfully.

Viva:

• What are the reasons for choosing linked list to solve polynomial addition?
Linked lists provide an elegant solution for efficiently handling polynomials due to
their dynamic memory allocation and straightforward implementation.

• Which data structure is used to represent a polynomial efficiently?


Representation of Polynomials is generally done using either arrays or linked lists.

• What is a list in Python?


A list is a data structure in Python that is a mutable, or changeable, ordered sequence
of elements.

• What is list operator in Python?


Insert() ...remove() ...Pop() ...Slice() ...reverse() ...
Ex.No:6b Application of Stack

Aim:

To implement the conversion of infix to postfix in stack.

Theory to practical mapping:

CO2: Design, implement, and analyse linear data structures, such as lists, queues, and stacks,
according to the needs of different applications.

Theory:

Postfix notation, also known as Reverse Polish Notation (RPN), offers a solution to the
problems associated with infix notation. In postfix notation, the operators are placed after their
corresponding operands, eliminating the need for parentheses and reducing ambiguity.

Algorithm:

Step 1:Read the given expression.


Step 2:check ifempty or not, the stack will insert the elements.
Step 3:Using push(), pop() to insert the element or remove the element.
Step 4:Check the operator based on the precedence the expression will be evaluated.
Step 5:Close the program.

Coding:

class Conversion:

def __init__(self, capacity):


self.top = -1
self.capacity = capacity

self.array = []
self.output = []
self.precedence = {'+':1, '-':1, '*':2, '/':2, '^':3}

def isEmpty(self):
return True if
self.top == -1
else False

def peek(self):
return self.array[-1]

def pop(self):
if not self.isEmpty():
self.top -= 1
return self.array.pop()
else:
return "$"

def push(self, op):


self.top += 1
self.array.append(op)

def isOperand(self, ch):


return ch.isalpha()

def notGreater(self, i):


try:
a = self.precedence[i]
b = self.precedence[self.peek()]
return True
if a <= b else False
except KeyError:
return False
def infixToPostfix(self, exp):

for i in exp:
if self.isOperand(i):
self.output.append(i)

elif i == '(': self.push(i) elif i == ')':


while( (not self.isEmpty()) and
self.peek() != '('):
a = self.pop()
self.output.append(a)
if (not self.isEmpty() and self.peek() != '('):
return -1
else:

self.pop()
else:
while(not self.isEmpty() and
self.notGreater(i)):
self.output.append(self.pop())
self.push(i)

while not self.isEmpty():


self.output.append(self.pop())
print "".join(self.output)

exp = "a+b*(c^d-e)^(f+g*h)-i"
obj = Conversion(len(exp))
obj.infixToPostfix(exp)

Output:

abcd^e-fgh*+^*+i-

Result:
Thus the conversion can be successfully executed.

Viva:

• What is infix stack?


Infix notation is the notation in which operators come between the required operands.

• What is the function of infix?


The infix notation is used in arithmetical and logical code. It is characterized by the
placement of operators between operands

• What is the advantage of infix to postfix?


Converting an infix expression to postfix notation allows for efficient evaluation and
simplifies expression parsing.

• What is postfix in stack?


Postfix notation is a way to represent an expression, where operators follow their
corresponding operands.

• Why postfix is better?


Postfix expression is simple to execute as a comparison to the infix expression it
required more operation to execute.
Ex.No:6c Application of Queue

Aim:

To implement the application of queue using FCFS CPU Scheduling.

Theory to practical mapping:

CO2: Design, implement, and analyse linear data structures, such as lists, queues, and
stacks, according to the needs of different applications.

Theory:

The full form of FCFS Scheduling is First Come First Serve Scheduling. FCFS
Scheduling algorithm automatically executes the queued processes and requests in the order
of their arrival. It allocates the job that first arrived in the queue to the CPU, then allocates
the second one, and so on.

Algorithm:

Step 1:Input the number of processes required to be scheduled using FCFS, burst time for
each process and its arrival time.

Step 2:Calculate the Finish Time, Turn Around Time and Waiting Time for each process
which in turn help to calculate Average Waiting Time and Average Turn Around Time
required by CPU to schedule given set of process using FCFS.
for i = 0, Finish Time T 0 = Arrival Time T 0 + Burst Time T 0

for i >= 1, Finish Time T i = Burst Time T i + Finish Time T i - 1

for i = 0, Turn Around Time T 0 = Finish Time T 0 - Arrival Time T 0

for i >= 1, Turn Around Time T i = Finish Time T i - Arrival Time T i

for i = 0, Waiting Time T 0 = Turn Around Time T 0 - Burst Time T 0

for i >= 1, Waiting Time T i = Turn Around Time T i - Burst Time T i - 1


Step 3:Process with less arrival time comes first and gets scheduled first by the CPU.
Step 4:Calculate the Average Waiting Time and Average Turn Around Time.
Step 5:Stop the program.
Coding:

def findWaitingTime(processes, n,bt, wt):

wt[0] = 0
for i in range(1, n ):
wt[i] = bt[i - 1] + wt[i - 1]

def findTurnAroundTime(processes, n,bt, wt, tat):

# calculating turnaround
# time by adding
bt[i] + wt[i]
for i in range(n):
tat[i] = bt[i] + wt[i]

def findavgTime( processes, n, bt):

wt = [0] * n
tat = [0] * n
total_wt = 0
total_tat = 0

findWaitingTime(processes, n, bt, wt)

findTurnAroundTime(processes, n, bt, wt, tat)


print( "Processes Burst time " + " Waiting time " + " Turn around
time")

for i in range(n):
total_wt = total_wt + wt[i]
total_tat = total_tat + tat[i]
print(" " + str(i + 1) + "\t\t" + str(bt[i]) + "\t " str(wt[i]) + "\t\t " +
str(tat[i]))

print( "Average waiting time = "+ str(total_wt / n))


print("Average turn around time = "+ str(total_tat / n))

if __name__ =="__main__":

processes = [ 1, 2, 3]
n = len(processes)
burst_time = [10, 5, 8]
findavgTime(processes, n, burst_time)

Output:

Processes Burst time Waiting time Turn around time


• 10 0 10
• 5 10 15
• 8 15 23
Average waiting time = 8.33333
Average turn around time = 16

Result:

Thus the FCFS CPU Scheduling was Executed Successfully.

Viva:

• How queue is used in CPU scheduling?


Each processing state has its own queue in the OS, and PCBs from all processes in
the same execution state are put in the very same queue.

• What is the full form of FCFS?


First Come, First Served (FCFS)

• Where is FCFS used?


First Come, First Served (FCFS) is a type of scheduling algorithm used by operating
systems and networks to efficiently and automatically execute queued tasks,
processes and requests by the order of their arrival.

• What is the application of CPU scheduling algorithm?


The main function of the CPU scheduling is to ensure that whenever the CPU
remains idle, the OS has at least selected one of the processes available in the ready-
to-use line.
Ex. No:7A Implementation of searching algorithms

Aim:

To implement searching using Linear and Binary Search algorithm using python.

Theory to practical mapping:

CO3: Design, implement, and analyse efficient sorting and searching to meet requirements
such as searching, indexing, and sorting

Theory:

Searching Algorithms are designed to check for an element or retrieve an element from
any data structure where it is stored. Linear Search sequentially checks each element in the
list until it finds a match or exhausts the list. Binary Search continuously divides the sorted
list, comparing the middle element with the target value.

Algorithm:

Linear Search:

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 matching, then display "Given element found!!!" and terminate the
function
Step 4:If both are not matching, then compare search element with the next element in the
list.
Step 5:Repeat steps 3 and 4 until the search element is compared with the last element in the
list.
Step 6:If the last element in the list is also doesn't match, then display "Element not found!!!"
and terminate the function.

Binary search:

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 matching, then display "Given element found!!!" and terminate the
function Step 5:If both are not matching, then check whether the search element is smaller
or larger than middle element.
Step 6:If the search element is smaller than middle element, then 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, then 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 not
found in the list!!!" and terminate the function.

Binary Search Coding:

def BinarySearch(arr, low, high, key):


if high >= low:
mid = (high + low) // 2

if (arr[mid] == key):
return mid
elif (arr[mid] > key):
return BinarySearch(arr, low, mid - 1, key)
else:
return BinarySearch(arr, mid + 1, high, key)
else:
return -1

arr = [ 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 ]
key = 40
result = BinarySearch(arr, 0, len(arr)-1, key)
if result != -1:
print(key, "Found at index", str(result))
else:
print(key, "not Found")

Linear Search Coding:

def linearsearch(arr, x):


for i in range(len(arr)):
if arr[i] == x:
return i
return -1
arr = ['t','u','t','o','r','i','a','l']
x = 'a'
print("element found at index "+str(linearsearch(arr,x)))

Output of Binary

Search: 40 Found at
index 3
Output of Linear Search:

element found at index 6

Result:
Thus the implementation of searching using Linear and Binary Search using python was
executed successfully.

Real Time application:

• In searching algorithm.
• Huffman coding is implemented with the help of BST.
• They are used in implementing dictionaries.
• They are used in spelling checking.
• BST is used for indexing in DBMS.
• They are also used in priority queues.

Viva:

• What are the applications of linear and binary search?


Linear search can be used on both single and multidimensional array, whereas the
binary search can be implemented only on the one-dimensional array.

• Which is faster linear or binary search?


Binary search is faster than linear when the given array is already sorted. For a sorted
array, binary search offers an average O(log n) meanwhile linear offers O(n).

• What is searching algorithm in Python?


It involves finding a specific element within a collection of data, such as an array or a
list.

• What are the search algorithm methods?


They can either be sequential (linear search) or interval-based (binary search).

• What are all the types of searching algorithm?


There are many types of searching algorithms possible like linear search, binary
search, jump search, exponential search, Fibonacci search, etc.
Ex.No:7B Implementation of Sorting Algorithm

Aim:

To Implement sorting Algorithm using Quick Sort and Insertion Sort algorithm using
python.

Theory to practical mapping:

CO3: Design, implement, and analyse efficient sorting and searching to meet requirements
such as searching, indexing, and sorting

Theory:

Quicksort algorithm is efficient if the size of the input is very large. But, insertion sort
is more efficient than quick sort in case of small arrays as the number of comparisons and
swaps are less compared to quicksort.

Algorithm:

Quick Sort:

Step 1:Find a “pivot” item in the array. This item is the basis for comparison for a single
round.
Step 2:Start a pointer (the left pointer) at the first item in the array.
Step 3:Start a pointer (the right pointer) at the last item in the array.
Step 4:While the value at the left pointer in the array is less than the pivot value, move
the left pointer to the right (add 1).
Step 5:Continue until the value at the left pointer is greater than or equal to the pivot
value.
Step 6:While the value at the right pointer in the array is greater than the pivot value,
move the right pointer to the left (subtract 1).
Step 7:Continue until the value at the right pointer is less than or equal to the pivot
value.
Step 8:If the left pointer is less than or equal to the right pointer, then swap the values at
these locations in the array.
Step 9:Move the left pointer to the right by one and the right pointer to the left by one.
Insertion Sort:

Step 1:Compare each element with preceding elements.


Step 2:Shift each compared element on the right.
Step 3:Place the element at the empty spot.
Step 4:Print the sorted array.

Coding of Quick Sort:

def partition(arr,low,high):
i = ( low-1 )
pivot = arr[high]
for j in range(low , high):

if arr[j] <= pivot:


i = i+1
arr[i],arr[j] = arr[j],arr[i]
arr[i+1],arr[high] = arr[high],arr[i+1]
return ( i+1 )

def quickSort(arr,low,high):
if low < high:

pi = partition(arr,low,high)
quickSort(arr, low, pi-1)
quickSort(arr, pi+1, high)

arr = [2,5,3,8,6,5,4,7]
n = len(arr)
quickSort(arr,0,n-1)
print ("Sorted array is:")
for i in range(n):
print (arr[i],end=" ")

Coding of Insertion Sort:

def insertionSort(arr):
for i in range(1, len(arr)):
key = arr[i]
j = i-1
while j >=0 and key < arr[j] :
arr[j+1] = arr[j]
j -= 1
arr[j+1] = key

arr = ['t','u','t','o','r','i','a','l']
insertionSort(arr)
print ("The sorted array is:")
for i in range(len(arr)):
print (arr[i])

Output:

Quick Sorted array


is: 2 3 4 5 5 6 7 8
Insertion sorted array is: a
i
l
o
r
t
t
u

Result:
Thus the implementation of searching Quick and Insertion Sort algorithm using python was
executed successfully.

Real Time application:

• Order things by their value.


• Backend Databases (Merge Sort).
• Playing Cards with your friends (Insertion Sort).
• sort() - uses IntroSort (a hybrid of Quicksort, Heapsort, and Insertion Sort), Faster
than qsort()
• The contact list on the phone.
• Online shopping.

Viva:

• What is a quick sort algorithm?


Quicksort is a divide-and-conquer algorithm.

• What is a insertion sort algorithm?


Insertion sort iterates, consuming one input element each repetition, and grows a
sorted output list.

• Which is better insertion or quick sort?


Insertion sort becomes faster if data is partially sorted. However, for large data set,
quicksort is way faster.

• Where is quick sort used in real life?


Call Optimization and Database management.
Ex.No:8 Implementation of Hash tables

Aim:

To Implement the Hash tables using python.

Theory to practical mapping:

CO3: Design, implement, and analyse efficient sorting and searching to meet requirements
such as searching, indexing, and sorting

Theory:

A hash table, also known as a hash map, is a data structure that maps keys to values.
It is one part of a technique called hashing, the other of which is a hash function. A hash
function is an algorithm that produces an index of where a value can be found or stored in
the hash table.

Algorithm:

Step 1:Create a structure, data (hash table item) with key and value as data.
Step 2:for loops to define the range within the set of elements.
Step 3:hashfunction(key) for the size of capacity.
Step 4:Using insert(),removal() data to be presented or
removed.
Step 5:Stop the program.

Coding:

hashTable = [[],] * 10
def checkPrime(n):
if n == 1 or n == 0:
return 0
for i in range(2, n//2):
if n % i == 0:
return 0
return 1
def getPrime(n):
if n % 2 == 0:
n=n+1
while not checkPrime(n):
n += 2
return n
def hashFunction(key):
capacity = getPrime(10)
return key % capacity
def insertData(key, data):
index = hashFunction(key)
hashTable[index] = [key, data] def removeData(key):
index = hashFunction(key)
hashTable[index] = 0
insertData(123, "apple")
insertData(432, "mango")
insertData(213, "banana")
insertData(654, "guava")
print(hashTable)
removeData(123)
print(hashTable)

Output:

[[], [], [123, 'apple'], [432, 'mango'], [213, 'banana'], [654, 'guava'], [], [], [],
[]] [[], [], 0, [432, 'mango'], [213, 'banana'], [654, 'guava'], [], [], [], []]

Result:

Thus the Implementation of hashing was executed successfully.

Real Time application:

Some of the more popular examples are username-password databases, integrity checks, and
blockchain verification.
• Verifying the integrity of messages and files. An important application of secure
hashes is the verification of message integrity. ...
• Signature generation and verification. ...
• Password verification. ...
• Proof-of-work. ...
• File or data identifier.

Viva:

• What is hash table?


A Hash table is defined as a data structure used to insert, look up, and remove key-
value pairs quickly.

• What is the concept of hashing?


Hashing is the process of transforming any given key or a string of characters into
another value.

• What is a hash table used for?


A hash table is a data structure that is used to store keys/value pairs.

• What is the advantage of hash table?


Hash tables are more efficient than search trees or other data structures.

• What are the disadvantages of hash tables?


collision resolution, variable performance, space overhead, lack of ordered data, and
dependency on a quality hash function.
Ex.No:9a Tree representation

Aim:

To implement tree representation in binary tree format.

Theory to practical mapping:

CO4: Design, implement, and analyse efficient tree structures to meet requirements such as
binary ADT, AVL and heaps.

Theory:

Trees are a fundamental concept in computer science and data structures used to solve
complex problems. Trees provide an efficient way of organizing, storing, and retrieving data.
They are versatile structures that can be used for sorting, searching, indexing, and traversal
applications.

Algorithm:

Step 1:Create a binary tree.


Step 2:Intially all the left and right vertex are none, then declare the values using insert()
function.
Step 3:If data>right element place the element in right.
Step 4:If data<left element place the element in left.
Step 5:Print the tree.
Step 6:Stop the program.

Coding:

class Node:
def __init__(self, data):
self.left = None
self.right = None
self.data = data
def insert(self, data):
if self.data:
if data < self.data:
if self.left is None:
self.left = Node(data)
else:

self.left.insert(data)
elif data > self.data:
if self.right is None:
self.right = Node(data)
else:
self.right.insert(data)
else:
self.data = data
def PrintTree(self):
if self.left:

self.left.PrintTree()
print( self.data), if
self.right:
self.right.PrintTree()
root = Node(12)
root.insert(6)
root.insert(14)
root.insert(3)
root.PrintTree()

Output:

3
6
12
14
Result:

Thus the binary tree was successfully created.

Real Time application:

• Artificial Intelligence: In AI, binary trees are used in decision tree algorithms for tasks
like classification and regression. They are also used in minimax algorithms for game
playing, such as in the construction of game trees for games like chess or tic-tac-toe.
• Data Compression: Huffman coding, a widely used algorithm for lossless data
compression, employs binary trees to generate variable-length codes for characters
based on their frequencies.
• Cryptography: Binary trees are used in cryptographic algorithms, such as Merkle trees
used in blockchain technology for efficient and secure verification of large datasets.
• Hierarchical Data Structures: Binary trees are used to represent hierarchical data
structures like organization charts, file systems, and XML/JSON parsing.
• Computer Graphics: Binary space partitioning trees (BSP trees) are used in computer
graphics for visibility determination and efficient rendering of scenes.
• Genetics and Evolutionary Biology: Binary trees are used in evolutionary biology for
representing phylogenetic trees, which depict evolutionary relationships between
species.

Viva:

• what is binary tree?


A binary tree is a hierarchical data structure composed of nodes, where each node has
at most two children, referred to as the left child and the right child. The topmost
node in a binary tree is called the root node. Each node can have zero, one, or two
children nodes.

• What is the representation of the tree in a binary tree?


• What are types of binary tree?
The different types of binary search trees include full, complete, perfect, degenerate,
and balanced.

• What are the two methods of binary tree implementation?


• Dynamic Node Representation (Linked Representation).
• Array Representation (Sequential Representation).
Ex.No:9b Tree Traversal Algorithms

Aim:

To Implement traversal using Inorder,Preorder,Postorder techniques.

Theory to practical mapping:

CO4: Design, implement, and analyse efficient tree structures to meet requirements such as
binary ADT, AVL and heaps.

Theory:

Tree traversal algorithms are used to visit and process all the nodes in a tree. There
are mainly three types of tree traversal algorithms:

• In-order Traversal:
In an in-order traversal, nodes are visited in the order: left child, root, right child.
For binary search trees (BSTs), in-order traversal visits the nodes in sorted order.

• Pre-order Traversal:
In a pre-order traversal, nodes are visited in the order: root, left child, right child.
This is often used to create a copy of the tree.

• Post-order Traversal:
In a post-order traversal, nodes are visited in the order: left child, right child, root.
This is often used in deleting the tree or evaluating expressions.

Algorithm:

Step 1:Inorder(tree)
• Traverse the left subtree, i.e., call Inorder(left-subtree)
• Visit the root.
• Traverse the right subtree, i.e., call Inorder(right-subtree)
Step 2:Preorder(tree)
• Visit the root.
• Traverse the left subtree, i.e., call Preorder(left-subtree)
• Traverse the right subtree, i.e., call Preorder(right-subtree)
Step 3:Postorder(tree)
• Traverse the left subtree, i.e., call Postorder(left-subtree)
• Traverse the right subtree, i.e., call Postorder(right-subtree)

Step 4:Visit the root

Coding:

class Node:
def __init__(self,key):
self.left = None
self.right = None
self.val = key
def printInorder(root):
if root:
printInorder(root.left)
print(root.val),
printInorder(root.right)

def printPostorder(root):
if root:
printPostorder(root.left)
printPostorder(root.right)
print(root.val),
def printPreorder(root):
if root:
print(root.val),
printPreorder(root.left)
printPreorder(root.right)
root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(4)
root.left.right = Node(5)
print ("\nPreorder traversal of binary tree is")
printPreorder(root)
print ("\nInorder traversal of binary tree is")
printInorder(root)
print ("\nPostorder traversal of binary tree is")
printPostorder(root)
Output:

Preorder traversal of binary tree is


1
2
4
5
3
Inorder traversal of binary tree is
4
2
5
1
3
Postorder traversal of binary tree is
4
5
2
3
1

Result:

Thus the Implementation of traversal using Inorder,Preorder,Postorder techniques was


executed successfully.

Real Time application:

Tree traversal algorithms, such as in-order, pre-order, and post-order traversals, are essential
for processing tree nodes in a specific order. They are used in various applications, including
expression evaluation, syntax parsing, and data manipulation.
Viva:

• What are the techniques of traversal?


There are three main traversal techniques: in-order, pre-order, and post-order
traversal.

• What is common in three different types of traversals?


The common characteristic among all three types of traversals is that the left subtree
is always visited before the right subtree.

• What is pre-order traversal technique?


The pre-order traversal is one of the most commonly used tree traversal algorithms.
As the name suggests, pre-order traversal visits each node in a tree before its child
nodes.

• What is post-order traversal technique?


Post-order traversal is defined as a type of tree traversal which follows the Left-
Right-Root policy such that for each node: The left subtree is traversed first.

• What is in-order traversal technique?


In-order traversal is defined as a type of tree traversal technique which follows the
Left-Root-Right pattern, such that: The left subtree is traversed first.
Ex.No:10 Implementation of Binary Search Trees

Aim:

To Implement the Binary Search Trees using python.

Theory to practical mapping:

CO4: Design, implement, and analyse efficient tree structures to meet requirements such as
binary ADT, AVL and heaps.

Theory:

Binary Search Trees (BSTs) are a type of binary tree where each node has at most
two children, and the left child is less than the parent node, while the right child is greater.
This property makes searching, insertion, and deletion operations very efficient.

Algorithm:

Step 1-Read the search element from the user.

Step 2 - Compare the search element with the value of root node in the tree.

Step 3 - If both are matched, then display "Given node is found!!!" and terminate the
function.

Step 4 - If both are not matched, then check whether search element is smaller or larger than
that node value.

Step 5 - If search element is smaller, then continue the search process in left subtree.

Step 6- If search element is larger, then continue the search process in right subtree.

Step 7 - Repeat the same until we find the exact element or until the search element is
compared with the leaf node.

Step 8 - If we reach to the node having the value equal to the search value then display
"Element is found" and terminate the function.
Coding:

class Node:
def __init__(self, data):
self.left = None
self.right = None
self.data = data

def insert(self, data):


if self.data:
if data < self.data:
if self.left is None:
self.left = Node(data)
else:

self.left.insert(data)
elif data > self.data:
if self.right is None:
self.right = Node(data)
else:
self.right.insert(data)
else:
self.data = data

def findval(self, lkpval):


if lkpval < self.data:
if self.left is None:
return str(lkpval)+" Not Found"
return self.left.findval(lkpval)
elif lkpval > self.data:
if self.right is None:
return str(lkpval)+" Not Found"
return self.right.findval(lkpval)
else:
print(str(self.data) + ' is found')

def PrintTree(self):
if self.left:

self.left.PrintTree()
print( self.data),
if self.right:
self.right.PrintTree()
root = Node(12)
root.insert(6)
root.insert(14)
root.insert(3)
print(root.findval(7))

Output:

7 Not Found
14 is found

Result:

Thus the Implementation of Binary Search Trees using python was executed successfully.

Real Time application:

• In searching algorithm.
• Huffman coding is implemented with the help of BST.
• They are used in implementing dictionaries.
• They are used in spelling checking.
• BST is used for indexing in DBMS.
• They are also used in priority queues.

Viva:

• What is a binary tree?


Binary search trees are non-linear data structures with a maximum of two children
for every parent node.

• What are binary types?


The different types of binary search trees include full, complete, perfect, degenerate,
and balanced.

• What are the applications of binary tree?


In computing, binary trees are mainly used for searching and sorting as they provide
a means to store data hierarchically.
• What are the advantages of a binary tree?
A BST is fast for most operations such as searching, insertion, and deletion, whereas
arrays provide fast searching, but are comparatively slow in insertion and deletion
operations.
Ex.NO:11 Implementation of Heaps

Aim:

To Implement the Heap algorithm using python.

Theory to practical mapping:

CO4: Design, implement, and analyse efficient tree structures to meet requirements such as
binary ADT, AVL and heaps.

Theory:

Heaps are tree-based data structures constrained by a heap property. Heaps are used
in many famous algorithms such as Dijkstra's algorithm for finding the shortest path, the
heap sort sorting algorithm, implementing priority queues, and more.

Algorithm:

Step 1:Insert the heap function in the list.


Step 2:using heappush(),heappop(),heapify() to insert ,delete,display the
elements.
Step 3:Stop the program.

Coding:

import heapq H = [21,1,45,78,3,5]


heapq.heapify(H)
print(H)
heapq.heappush(H,8)
print(H)
heapq.heappop(H)
print(H)
Output:

1, 3, 5, 78, 21, 45
[1, 3, 5, 78, 21, 45, 8]
[3, 8, 5, 78, 21, 45]

Result:

Thus the Implementation of the Heap algorithm was executed succeefully.

Real Time application:

• Priority Queue: Heap is used in the construction of the priority queue efficiently.
You can easily insert, delete, and identify priority elements, or you can insert and
extract the element with priority in the time complexity of O(log n).
• Graph Algorithms: Heap Implemented priority queues are also used in graph
algorithms, such as Dijkstra’s algorithm and prim’s algorithm.
• Order Statistics: We can easily use Heap data structures to find the kth largest/
smallest element in the array.
• Embedded System: We can use heap data structure effectively in systems concerned
with security and also in embedded systems such as Linux kernel.

Viva:

• What is heap data structure?


A Heap is a special Tree-based data structure in which the tree is a complete binary
tree.

• What are Operations of Heap Data Structure?


Heapify, Insertion, Deletion, Peek.
• What are Types of Heap Data Structure?
Max-Heap and Min-Heap.

• What is the advantage of heap?


Heaps are efficient because they can retrieve, insert, and delete elements in O(log n)
time, which is faster than the O(n) time required by a linear search.
Ex.No:12a Graph representation

Aim:

To implement the graph representation using python.

Theory to practical mapping:

CO5: Model problems as graph problems and implement efficient graph algorithms to solve
them

Theory:

Graphs in data structures are used to represent the relationships between objects.
Every graph consists of a set of points known as vertices or nodes connected by lines known
as edges. The vertices in a network represent entities.

Algorithm:

Step 1: import dictionary for graph


Step 1: function for adding edge to graph
Step 1: definition of function
Step 1: for each node in graph
Step 1: for each neighbour node of a single node
Step 1: if edge exists then append
Step 1: declaration of graph as dictionary
Step 1: Driver Function call to print generated graph
Step 1: Stop the program.

Coding:

class graph:
def__init__(self,gdict=Non):
if gdict is None:
gdict = []
self.gdict = gdict
def getVertices(self):
return list(self.gdict.keys())
graph_elements = { "a" : ["b","c"],
"b" : ["a", "d"],
"c" : ["a", "d"],
"d" : ["e"],
"e" : ["d"]
}
g = graph(graph_elements)
print(g.getVertices())
class graph:
def__init__(self,gdict=Non):
if gdict is None:
gdict = {}
self.gdict = gdict
def edges(self):
return self.findedges()
def findedges(self):
edgename = []
for vrtx in self.gdict:
for nxtvrtx in self.gdict[vrtx]:
if {nxtvrtx, vrtx} not in edgename:
edgename.append({vrtx, nxtvrtx})
return edgename
graph_elements = { "a" : ["b","c"],
"b" : ["a", "d"],
"c" : ["a", "d"],
"d" : ["e"],
"e" : ["d"]
}
g = graph(graph_elements)
print(g.edges())

Output:

DISPLAYING VERTICES
['a', 'b', 'c', 'd', 'e']
DISPLAYING EDGES
[{'a', 'b'}, {'a', 'c'}, {'d', 'b'}, {'c', 'd'}, {'d', 'e'}]
Result:

Thus the implementation of graphs was executed successfully.

Real Time application:

Some of the real-life applications of graph data structure include Social Graphs, Knowledge
Graphs, Path Optimization Algorithms, Recommendation Engines, and Scientific
Computations.

Viva:

• What is graph representation in data structure?


Graphs in data structures are used to represent the relationships between objects.

• What is graph type in data structure?


Simple Graph, Multi Graph and Null Graph.

• What are the advantages of graph data structure?


The three advantages of graphs are as follows: It makes data presentable and easy to
understand. It helps in summarizing the data in a crisp manner. It helps in the
comparison of data in a better way.

• What are disadvantages of graph?


They can be misleading, confusing, or inaccurate if they are not designed, labeled, or
interpreted correctly.
Ex.No:12b Graph Traversal Algorithms

Aim:

To Implement using BFS,DFS can be traversed.

Theory to practical mapping:

CO5: Model problems as graph problems and implement efficient graph algorithms to solve
them

Theory:

There are two main algorithms to traverse all nodes in a graph:


(1) DFS, focusing on traversing nodes by depth, before moving to the next level nodes; and
(2) BFS, focusing on traversing nodes by width within the same level, before moving to the
next depth level in the graph.

Algorithm:

DFS:

Step 1 - Define a Stack of size total number of vertices in the graph.

Step 2 - Select any vertex as starting point for traversal. Visit that vertex and push it on to the
Stack.

Step 3 - Visit any one of the non-visited adjacent vertices of a vertex which is at the top of
stack and push it on to the stack.

Step 4 - Repeat step 3 until there is no new vertex to be visited from the vertex which is at
the top of the stack.

Step 5 - When there is no new vertex to visit then use back tracking and pop one vertex from
the stack.

Step 6 - Repeat steps 3, 4 and 5 until stack becomes Empty.

Step 7 - When stack becomes Empty, then produce final spanning tree by removing unused
edges from the graph
BFS:

Step 1 - Define a Queue of size total number of vertices in the graph.

Step 2 - Select any vertex as starting point for traversal. Visit that vertex and insert it into the
Queue.

Step 3 - Visit all the non-visited adjacent vertices of the vertex which is at front of the Queue
and insert them into the Queue.

Step 4 - When there is no new vertex to be visited from the vertex which is at front of the
Queue then delete that vertex.

Step 5 - Repeat steps 3 and 4 until queue becomes empty.

Step 6 - When queue becomes empty, then produce final spanning tree by removing unused
edges from the graph

BFS

Output:

Following is Breadth First Traversal:


0123

DFS

Output:

FOUND: J
['A', 'D', 'F', 'G', 'I']
Result:

Thus the implementation of using BFS,DFS graph can be traversed.

Real Time application:

• finding all vertices within one connected component;


• Cheney's algorithm;
• finding the shortest path between two vertices;
• testing a graph for bipartiteness;
• Cuthill–McKee algorithm mesh numbering;
• Ford–Fulkerson algorithm for computing the maximum flow in a flow network;

Viva:

• What are the algorithms for traversing a graph?


Two algorithms are generally used for the traversal of a graph: Depth first search
(DFS) and Breadth first search (BFS).

• What is the algorithm of DFS and BFS?


BFS (Breadth-first search) is a network search method that investigates all
surrounding nodes after starting at the root node. DFS (Depth initial search) is an
algorithm that starts with the first node in the network and continues to explore until
it discovers the desired node or even a node with no children.

• Which is better DFS or BFS?


BFS works better when a user searches for the vertices that stay closer to any given
source. DFS works better when a user can find the solutions away from any given
source.

• What is the difference between BFS and DFS graph traversal?


BFS explores the graph level by level, while DFS explores the graph by going as
deep as possible along each branch.

• What are the advantages of BFS and DFS?


BFS is also useful for finding the level or depth of each node in the graph, whereas
DFS is better for finding the topological order or post-order of the graph.
Ex.No:13 Implementation of single source shortest path algorithm

Aim:

To Implement single source shortest path algorithm using Bellman Ford Algorithm.

Theory to practical mapping:

CO5: Model problems as graph problems and implement efficient graph algorithms to solve
them

Theory:

The Single-Source Shortest Path (SSSP) problem consists of finding the shortest paths
between a given vertex v and all other vertices in the graph. Algorithms such as Breadth-
First-Search (BFS) for unweighted graphs or Dijkstra solve this problem.

Algorithm:

Step 1:This step initializes distances from source to all vertices as infinite and distance to
source itself as 0.
Step 2:Create an array dist[] of size |V| with all values as infinite except dist[src] where src is
source vertex.
Step 3:This step calculates shortest distances.
Step 4:Do following |V|-1 times where |V| is the number of vertices in given graph.
Step 5:Do following for each edge u-v
If dist[v] > dist[u] + weight of edge uv, then update dist[v]
dist[v] = dist[u] + weight of edge uv
Step 6:This step reports if there is a negative weight cycle in graph.
Step 7:Do following for each edge u-v
If dist[v] > dist[u] + weight of edge uv, then “Graph contains negative weight cycle” The
idea of step 3 is, step 2 guarantees shortest distances if graph doesn’t contain negative
weight cycle. If we iterate through all edges one more time and get a shorter path for any
vertex, then there is a negative weight cycle.
Output:

Vertex Distance from Source


• 0
• -1 2

2
3 -2

Result:

Thus the Implementation of single source shortest path algorithm was successfully executed.

Real Time application:

• Examining a graph for the presence of negative weight cycles.


• Using negative weights, find the shortest path in a graph.
• Routing used in data networks.
• Routing Information Protocol (RIP) and
• the Border Gateway Protocol (BGP).
Viva:

• What is the Bellman-Ford algorithm?


The Bellman-Ford algorithm is a graph search algorithm that finds the shortest path
between a given source vertex and all other vertices in the graph.

• What is single source all shortest paths?


To find shortest paths from a source vertex v to all other vertices in the graph.

• What is the fastest algorithm for single source shortest path?


This generalization is called the generic Dijkstra shortest-path algorithm.

• What is the advantages of bellman ford algorithm?


It can handle graphs with some edge weights that are negative numbers.

• What are the disadvantages of the Bellman-Ford algorithm?


The algorithm has a time complexity of O(V*E), where V is the number of vertices
and E is the number of edges in the graph. This makes it less efficient.
Ex.No:14 Implementation of minimum spanning tree algorithms

Aim:

To implement the minimum spanning tree algorithms using Kruskal Algorithm.

Theory to practical mapping:

CO5: Model problems as graph problems and implement efficient graph algorithms to solve
them

Theory:

In Kruskal's algorithm, sort all edges of the given graph in increasing order. Then it
keeps on adding new edges and nodes in the MST if the newly added edge does not form a
cycle. It picks the minimum weighted edge at first and the maximum weighted edge at last.

Algorithm:

Step 1:Label each vertex


Step 2:List the edges in non-decreasing order of weight.
Step 3:Start with the smallest weighted and beginning growing the minimum weighted
spanning tree from this edge.
Step 4:Add the next available edge that does not form a cycle to the construction of the
minimum weighted spanning tree.
Step 5:If the addition of the next least weighted edge forms a cycle, do not use it.
Step 6:Continue with step 4 until you have a spanning tree.

Coding:

class Graph: d
ef __init__(self, vertices):
self.V = vertices
self.graph = []
def add_edge(self, u, v, w):
self.graph.append([u, v, w])
def find(self, parent, i):
return self.find(parent, parent[i])
def apply_union(self, parent, rank, x,
y):
xroot = self.find(parent, x)
yroot = self.find(parent, y)
if rank[xroot] < rank[yroot]:
parent[xroot] = yroot
elif rank[xroot] > rank[yroot]:
parent[yroot] = xroot
else:
parent[yroot] = xroot
rank[xroot] += 1
def kruskal_algo(self):
result = []
i, e = 0, 0
self.graph = sorted(self.graph,
key=lambda item: item[2])
parent = []
rank = []
for node in range(self.V):
parent.append(node)
rank.append(0)
while e < self.V - 1:
u, v, w = self.graph[i]
i=i+1
x = self.find(parent, u)
y = self.find(parent, v)
if x != y:
e=e+1
result.append([u, v, w])
self.apply_union(parent, rank, x, y)
for u, v, weight in result:
print("%d - %d: %d" % (u, v,
weight)) g = Graph(6)
g.add_edge(0, 1, 4)
g.add_edge(0, 2, 4)
g.add_edge(1, 2, 2)
g.add_edge(1, 0, 4)
g.add_edge(2, 0, 4)
g.add_edge(2, 1, 2)
g.add_edge(2, 3, 3)
g.add_edge(2, 5, 2)
g.add_edge(2, 4, 4)
g.add_edge(3, 2, 3)
g.add_edge(3, 4, 3)
g.add_edge(4, 2, 4)
g.add_edge(4, 3, 3)
g.add_edge(5, 2, 2)
g.add_edge(5, 4, 3)
g.kruskal_algo()

Output:

1 - 2: 2
2 - 5: 2
2 - 3: 3
3 - 4: 3
0 - 1: 4

Result:

Thus the program was executed successfully.

Real Time application:

• Landing cables.
• TV Network.
• Tour Operations.
• LAN Networks.
• A network of pipes for drinking water or natural gas.
• An electric grid.
• Single-link Cluster.

Viva:

• What is the Kruskal algorithm for the minimum spanning tree?


In Kruskal's algorithm, sort all edges of the given graph in increasing order.

• What are the two algorithms used to minimum spanning trees?


Prim's or Kruskal's.

• Which is better Prims or Kruskal?


The advantage of Prim's algorithm is its complexity, which is better than Kruskal's
algorithm.

• What is time complexity of Kruskal algorithm?


Kruskal's algorithm's time complexity is O(E log V), V being the number of vertices.

• What are the advantages and disadvantages of kruskal algorithm?


In graphs with dense or uniform edge weights, Kruskal's Algorithm may not provide
significant performance advantages over other minimum spanning tree algorithms.

You might also like