Data Structure & Algorithms Lab Manual V1.2-1
Data Structure & Algorithms Lab Manual V1.2-1
INDEX
Lab Course
Date Particulars Instructor Teacher
Signature Signature
Lab 8: Stack
Lab 9: Recursion
Lab 1
Programming Fundamentals with Python
Why use Python?
Python is easy to use, powerful, and versatile, making it a great choice for beginners and experts
alike. Python’s readability makes it a great first programming language — it allows you to think
like a programmer and not waste time with confusing syntax. For instance, look at the following
code to print “hello world” in Java, c# and Python.
Being a very high level language, Python reads like English, which takes a lot of syntax-learning
stress off coding beginners. Python handles a lot of complexity for you, so it is very beginner-
friendly in that it allows beginners to focus on learning programming concepts and not have to
worry about too much details.
Machine Learning
Deep Learning
Computer Vision
Data Science
Big Data Analytics
Automation Engineer
Data Analysis
Data Engineer
ETL Engineer
4. Now open command prompt (Write cmd on Run and press Enter)
5. Change directory to your desktop or where you saved your file.
6. Now write DIR and check to file exist in this folder or not.
7. Now write python and filename with extension and press enter.
Variables in Python
Variables are containers for storing data values. Unlike other programming languages, Python
has no command for declaring a variable. A variable is created the moment you first assign a
value to it. Variables do not need to be declared with any particular type and can even change
type after they have been set.
Example: 1.1
Example: 1.2
Example: 1.3
int() - constructs an integer number from an integer literal, a float literal (by rounding
down to the previous whole number), or a string literal (providing the string represents
a whole number)
float() - constructs a float number from an integer literal, a float literal or a string literal
(providing the string represents a float or an integer)
str() - constructs a string from a wide variety of data types, including strings, integer
literals and float literals
Example: 1.4
Example: 1.5
Example: 1.6
Example: 1.7
input() : This function first takes the input from the user and then evaluates the
expression, which means Python automatically identifies whether user entered a string
or a number or list. If the input provided is not correct then either syntax error or
exception is raised by python. For example –
Example: 1.8
Example: 1.10
Example: 1.11
Example: 1.15
Example: 1.16
In a company an employee is paid as: if basic salary of employee is less than Rs. 15,000, then
Rental Allowance = 10% of basic salary and dining Allowance = 90% of basic salary. If his salary
is either equal to or above Rs. 15,000 but less than Rs. 20,000 then Rental Allowance = Rs. 500
and dining Allowance = 98% of basic salary. Write a program such that, if the employee’s salary
is input through the keyboard write a program to find his gross salary.
For loop
The for loop in Python is used to iterate over a sequence (list, tuple, string, array) or other
iterable objects. Iterating over a sequence is called traversal.
Here, val is the variable that takes the value of the item inside the sequence on each iteration.
Loop continues until we reach the last item in the sequence. The body of for loop is separated
from the rest of the code using indentation.
Example: 1.17
This function does not store all the values in memory, it would be inefficient. So it remembers
the start, stop, step size and generates the next number on the go.
Example: 1.18
for x in range(10):
print(x)
We can use the range() function in for loops to iterate through a sequence of numbers. It can
be combined with the len() function to iterate though a sequence using indexing. Here is an
example.
Example: 1.19
Example: 1.20
digits = [0, 1, 5]
for i in digits:
print(i)
else:
print("No items left.")
Here, the for loop prints items of the list until the loop exhausts. When the for loop exhausts, it
executes the block of code in the else and prints
while loop
The while loop in Python is used to iterate over a block of code as long as the test expression
(condition) is true. We generally use this loop when we don't know beforehand, the number of
times to iterate.
Syntax of while Loop in Python
while test_expression:
Body of while
In while loop, test expression is checked first. The body of the loop is entered only if the test
expression evaluates to True. After one iteration, the test expression is checked again. This
process continues until the test expression evaluates to False.
In Python, the body of the while loop is determined through indentation. Body starts with
indentation and the first unindented line marks the end.
Python interprets any non-zero value as True. None and 0 are interpreted as False.
Example: 1.21
sum = 0
i = 1
while i <= n:
sum = sum + i
i = i+1 # update counter
# print the sum
print("The sum is", sum)
In the above program, the test expression will be True as long as our counter variable i is less
than or equal to n (10 in our program).
We need to increase the value of counter variable in the body of the loop. This is very
important (and mostly forgotten). Failing to do so will result in an infinite loop (never ending
loop).
Example: 1.22
# Example to illustrate
# the use of else statement
# with the while loop
counter = 0
while counter < 3:
print("Inside loop")
counter = counter + 1
else:
print("Inside else")
Flowchart of break
Example: 1.23
Flowchart of continue
Example: 1.24
This program is same as the above example except the break statement has been replaced with
continue. We continue with the loop, if the string is "i", not executing the rest of the block.
Hence, we see in our output that all the letters except "i" gets printed.
Nested Loops:
Python programming language allows using one loop inside another loop. Following section
shows few examples to illustrate the concept.
Syntax:
The syntax for a nested while loop statement in Python programming language is as follows:
while expression:
while expression:
statement(s)
statement(s)
Example: 1.25
Lab 1 Exercises:
3. At IMTIAZ SUPER STORE, while purchasing certain items, customer gets a discount of
10% only if the quantity of all purchased items is more than Rs. 5,000. If Quantity and
price per item are input through the keyboard, write a program to calculate the total
bill.
4. If Cost Price and Selling Price if an item is input through the keyboard, write a program
to that tells seller is at profit or loss? Further, it should ask user to enter ‘c’ if s/he wants
to know how much profit or loss seller incurred.
5. A library charges a fine for every book returned late. For first 5 days the fine is 50 Rs, for
6-10 days fine is 100 rupee and above 10 days fine is 150 rupees. If you return the book
after 30 days your membership will be cancelled. Write a program to accept the number
of days the member is late to return the book and display the fine or the appropriate
message.
10. Write a program to print square star(*) pattern series of n rows. For example if n=5 the
star pattern should be printed like.
*****
*****
*****
*****
*****
Lab 2
Arrays
Arrays are vital for most programming languages. They are collections of variables, which
we call elements:
Python does not have built-in support for Arrays. But we use numpy library to use array.
An array’s elements in Python numpy library are numbered with 0, 1, 2, … N-1. Those
numbers are called indices.
The total number of elements in a given array we call length of an array.
All elements of a given array are of the same type.
This allows us to represent a group of similar elements as an ordered sequence and work
on them as a whole.
Arrays can be in different dimensions, but the most used are the one-dimensional and the
two-dimensional arrays.
One-dimensional arrays are also called vectors and two-dimensional are also known as
matrices.
Practical Demonstration
Example: 2.1
import numpy as np
FirstArray = np.array([1,2,3])
print(FirstArray[0]);
print(FirstArray[1]);
print(FirstArray[2]);
Example: 2.2
import numpy as np
FirstArray = np.arange(3)
print(FirstArray[0]);
print(FirstArray[1]);
print(FirstArray[2]);
Example: 2.3
import numpy as np
FirstArray = np.array([0 for i in range(4)])
print(FirstArray)
Example: 2.4
import numpy as np
a = np.array(['Furqan', 'Umer Aslam', 'Asim'])
print(a)
a[1] = 'Zeeshan'
print(a)
Practical Demonstration
Example: 2.5
import numpy as np
FirstArray = np.array([0 for i in range(5)])
length = len(FirstArray);
for i in range(length):
FirstArray[i] = i + 1;
for i in FirstArray:
print(i)
Example: 2.6
import numpy as np
for i in range(len(playersName)):
print()
playersName[i] = input(f"Enter Player {(i+1)} Name: ")
print("Players Name");
print("------------");
for i in playersName:
print(i)
Practical Demonstration
Example: 2.7
import numpy as np
for i in range(N):
LA[i] = int(input(f"Enter Value of Index {i}: "))
PrintArray(LA, N)
Example: 2.8
import numpy as np
Numbers = np.array([11,22,33,44,55])
for i in range(len(Numbers)):
print(Numbers[i], end=" ")
j = 0
for i in range(len(temp)):
if (i == Index):
temp[i] = value
else:
temp[i] = Numbers[j]
j += 1
Numbers = temp
for i in range(len(Numbers)):
print(Numbers[i], end=" ")
Practical Demonstration
Example: 2.9
import numpy as np
for i in range(N):
LA[i] = int(input(f"Enter value of index: {(i+1)} : "))
print("------------");
for i in range(N):
print(LA[i], end=" ")
for i in range(N):
print(LA[i], end=" ")
Example: 2.10
import numpy as np
Numbers = np.array([11,12,13,14,15])
for i in range(len(Numbers)):
print(Numbers[i], end=" ")
j = 0
for i in range(len(Numbers)):
if i == Index:
continue
else:
Temp[j] = Numbers[i]
j += 1
Numbers = Temp
for i in range(len(Numbers)):
print(Numbers[i], end=" ")
Practical Demonstration
Example: 2.11
import numpy as np
from timeit import Timer
size_of_vec = 1000
X_list = range(size_of_vec)
Y_list = range(size_of_vec)
X = np.arange(size_of_vec)
Y = np.arange(size_of_vec)
def pure_python_version():
Z = [X_list[i] + Y_list[i] for i in range(len(X_list)) ]
def numpy_version():
Z = X + Y
timer_obj1 = Timer("pure_python_version()",
"from __main__ import pure_python_version")
timer_obj2 = Timer("numpy_version()",
"from __main__ import numpy_version")
print(timer_obj1.timeit(200))
print(timer_obj2.timeit(200)) # Runs Faster!
print(timer_obj1.repeat(repeat=3, number=200))
print(timer_obj2.repeat(repeat=3, number=200)) # repeat to prove
it!
Lab 2 Exercises:
1. Write a program that will take 11 players name from user and save them in an array of
string and print all names on end.
2. Write a program that generate 20 random numbers and save them in an array, after
that Find the highest Number, lowest number and average from array.
3. A small shop sells 280 different items. Each item is identified by a 3 – digit code.
4. Write a program that lets a maker of chips and salsa keep track of their sales for five
different types of salsa they produce: mild, medium, sweet, hot, and zesty. It should use
two parallel five-element arrays: an array of strings that holds the five salsa names and
an array of integers that holds the number of jars sold during the past month for each
salsa type. The salsa names should be stored using an initialization list at the time the
name array is created. The program should prompt the user to enter the number of jars
sold for each type. Once this sales data has been entered, the program should produce a
report that displays sales for each salsa type, total sales, and the names of the highest
selling and lowest selling products.
5. A left rotation operation on an array of size n shifts each of the array's elements 1 unit
to the left. For example, if 2 left rotations are performed on array [1,2,3,4,5] , then the
array would become [3,4,5,1,2]
When we perform 4 left rotations, the array undergoes the following sequence of
changes:
Write code for a procedure that given an array of n integers and a number, d, performs
d left rotations on the array. Then return resulted array.
LAB 3
Multidimensional Arrays
2-dimensional arrays provide most of this capability. Like a 1D array, a 2D array is a collection of
data cells, all of the same type, which can be given a single name. However, a 2D array is
organized as a matrix with a number of rows and columns.
Example: 3.1
Numbers = array([[11,12,13],
[21,22,23],
[31,32,33]
])
print(Numbers[1,1])
Example: 3.2
print(Numbers)
Numbers[2,3] = 44;
Numbers[0,0] = 11;
print(Numbers)
Example: 3.3
for i in range(len(Players)):
for j in range(len(Players[i])):
Players[i, j] = input(f"Enter Team {i+1} Player {j+1}
Name: ")
for i in range(len(Players)):
print("Team: " + str(i+1) + " Player's Names")
for j in range(len(Players[i])):
print(Players[i, j], end=" ")
print()
Example: 3.4
Example: 3.5
from numpy import array
Numbers = array([
[
[1, 1],
[2, 2],
[3, 3]
],
[
[4, 4],
[5, 5],
[6, 6]
],
])
print(Numbers[1,2,0])
Example: 3.6
for i in range(len(ThreeDimensionalArray)):
for j in range(len(ThreeDimensionalArray[i])):
for k in range(len(ThreeDimensionalArray[i, j])):
print(ThreeDimensionalArray[i,j,k], end=" ")
print()
print()
Lab-3 Exercises:
1. Create a two dimensional array that can store below values in same rows and columns.
Get value from user input and store in array after that using for-loop, program to show a
below multiplication table.
1 2 3 4 5 6 7 8 9
2 4 6 8 10 12 14 16 18
3 6 9 12 15 18 21 24 27
4 8 12 16 20 24 28 32 36
5 10 15 20 25 30 35 40 45
6 12 18 24 30 36 42 48 54
7 14 21 28 35 42 49 56 63
8 16 24 32 40 48 56 64 72
9 18 27 36 45 54 63 72 81
Write a program that will calculate its product and print the resultant matrix.
4. Given a square matrix, calculate the absolute difference between the sums of its
diagonals.
For example, the square matrix is shown below:
123
456
989
The left-to-right diagonal = 1+5+9=15.
The right to left diagonal = 3+5+9 = 17
Their absolute difference is |15-17| = 2
Provide C# code for the function DiagonalDifference(). It must return an integer
representing the absolute diagonal difference.
DiagonalDifference takes the following parameter: arr: a 2D array of integers.
5. A local zoo wants to keep track of how many pounds of food each of its three monkeys
eats each day during a typical week. Stores this information in a two dimensional 3 × 7
array, where each row represents a different monkey and each column represents a
different day of the week. First let the user input the data for each monkey then it
should create a report that includes the following information:
Average amount of food eaten by each monkey for the whole week.
The least amount of food eaten during the week by any one monkey.
The greatest amount of food eaten during the week by any one monkey.
6. Write an algorithm that calculates the total score for students in a class. Suppose the
scores are stored in a three-dimensional array named scores. The first index in scores
refers to a student, the second refers to an exam, and the third refers to the part of the
exam. Suppose there are 7 students, 5 exams, and each exam has two parts--the
multiple-choice part and the programming part. So, scores[i][j][0] represents the score
on the multiple-choice part for the i’th student on the j’th exam. Your algorithm should
display the total score (all exams collectively) for each student.
LAB 4
Sorting Algorithms
Sorting is the process of placing elements from a collection in some kind of order. For example,
a list of words could be sorted alphabetically or by length. A list of cities could be sorted by
population, by area, or by zip code.
There are many sorting algorithms that have been developed and analyzed. This suggests that
sorting is an important area of study in computer science. Sorting a large number of items can
take a substantial amount of computing resources. Like searching, the efficiency of a sorting
algorithm is related to the number of items being processed. For small collections, a complex
sorting method may be more trouble than it is worth. The overhead may be too high. On the
other hand, for larger collections, we want to take advantage of as many improvements as
possible.
Before getting into specific algorithms, we should think about the operations that can be used
to analyze a sorting process. First, it will be necessary to compare two values to see which is
smaller (or larger). In order to sort a collection, it will be necessary to have some systematic
way to compare values to see if they are out of order. The total number of comparisons will be
the most common way to measure a sort procedure. Second, when values are not in the
correct position with respect to one another, it may be necessary to exchange them. This
exchange is a costly operation and the total number of exchanges will also be important for
evaluating the overall efficiency of the algorithm.
There are many type of sorting algorithms available on different resources. Here we are
learning some basic sorting algorithms like
1. Bubble Sort
2. Selection Sort
3. Insertion Sort
4. Counting Sort
Bubble Sort
Bubble Sort is a simple algorithm which is used to sort a given set of n elements provided in
form of an array with n number of elements. Bubble Sort compares the entire element one by
one and sort them based on their values.
If the given array has to be sorted in ascending order, then bubble sort will start by comparing
the first element of the array with the second element, if the first element is greater than the
second element, it will swap both the elements, and then move on to compare the second and
the third element, and so on.
If we have total n elements, then we need to repeat this process for n-1 times.
It is known as bubble sort, because with every complete iteration the largest element in the
given array, bubbles up towards the last place or the highest index, just like a water bubble
rises up to the water surface.
Sorting takes place by stepping through all the elements one-by-one and comparing it with the
adjacent element and swapping them if required.
i) Compare adjacent elements. If the first is greater than second, swap them.
ii) Repeat it for each adjacent pair of elements, starting with the first two and ending
with the last two. At this point the last element should be greatest.
iii) Repeat the steps for all elements except the last element.
iv) Keep repeating for one fewer elements each time until there are no pairs to
compare.
Practical Demonstration
Example: 4.1
import numpy as np
Numbers = np.array([1,5,2,4,3,6]);
print(Numbers)
print(Numbers)
Although the above logic will sort an unsorted array, still the above algorithm is not efficient
because as per the above logic, the outer for loop will keep on executing for 5 iterations even if
the array gets sorted after the second iteration.
So, we can clearly optimize our algorithm.
Hence, in the inner for loop, we check whether swapping of elements is taking place or not,
every time.
If for a particular iteration, no swapping took place, it means the array has been sorted and we
can jump out of the for loop, instead of executing all the iterations.
Let's consider an array with values {1, 5, 2, 4, 3, 6}
As we can see, in the first iteration, swapping took place, hence we updated our flag value
to true, as a result, the execution enters the for loop again. In the second iteration, swapping
took place again, hence we updated our flag value to true, as a result, the execution enters
the for loop again. But in the third iteration, no swapping will occur, hence the value of flag will
remain false, and execution will break out of loop.
Practical Demonstration
Example: 4.2
import numpy as np
Numbers = np.array([1, 5, 2, 4, 3, 6 ])
print(Numbers)
if (not flag):
break;
#Print Array
print(Numbers)
def SortStringArray(LA):
for i in range(len(LA) - 1):
for j in range(len(LA) - 1 - i):
if (LA[j][0] > LA[j+1][0]):
temp = LA[j]
LA[j] = LA[j+1]
LA[j+1] = temp
SortStringArray(Countries)
print(Countries)
Selection Sort
Selection sort is conceptually the simplest sorting algorithm. This algorithm will first find
the smallest element in the array and swap it with the element in the first position, then it will
find the second smallest element and swap it with the element in the second position, and it
will keep on doing this until the entire array is sorted.
It is called selection sort because it repeatedly selects the next-smallest element and swaps it
into the right place.
Following are the steps involved in Selection Sort (for sorting a given array in ascending order):
i) Starting from the first element, we search the smallest element in the array, and
replace it with the element in the first position.
ii) We then move on to the second position, and look for smallest element present in
the subarray, starting from index 1, till the last index.
iii) We replace the element at the second position in the original array, or we can say at
the first position in the subarray, with the second smallest element.
iv) This is repeated, until the array is completely sorted.
Practical Demonstration
Example: 4.4
import numpy as np
Numbers = np.array([1,5,2,4,3,6])
print(Numbers)
if Numbers[i] != Numbers[index]:
temp = Numbers[i]
Numbers[i] = Numbers[index]
Numbers[index] = temp
print(Numbers)
Example: 4.5
TowDArray = array([
["5122", "Furqan"],
["6123", "Umer"],
["5111", "Ali"]
])
print(TowDArray)
temp = array(TowDArray[index])
TowDArray[index] = TowDArray[i]
TowDArray[i] = temp;
print(TowDArray)
Insertion Sort
Consider you have 10 cards out of a deck of cards in your hand. And they are sorted, or
arranged in the ascending order of their numbers. If I give you another card, and ask you
to insert the card in just the right position, so that the cards in your hand are still sorted. What
will you do?
Well, you will have to go through each card from the starting or the back and find the right
position for the new card, comparing its value with each card. Once you find the right position,
you will insert the card there. Similarly, if more new cards are provided to you, you can easily
repeat the same process and insert the new cards and keep the cards sorted too.
This is exactly how insertion sort works. It starts from the index 1 (not 0), and each index
starting from index 1 is like a new card, that you have to place at the right position in the sorted
subarray on the left.
Algorithm Steps of Insertion Sort
Following are the steps involved in Insertion Sort (for sorting a given array in ascending order):
i) We start by making 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 (remember the example with cards above).
ii) We compare the key element with the element(s) before it, in this case, element at
index 0:
iii) If the key element is less than the first element, we insert the key element before
the first element.
iv) If the key element is greater than the first element, then we insert it after the first
element.
v) Then, we make the third element of the array as key and will compare it with
elements to its left and insert it at the right position.
vi) And we go on repeating this, until the array is sorted.
Practical Demonstration
Example: 4.6
from numpy import array
print(Numbers)
Example: 4.7
StudentNames[index] = temp
print(StudentNames)
Counting sort
Counting Sort is much different from Bubble, Selection & Insertion Sorting algorithms. In this
algorithm, comparison between elements doesn’t happen. Counting sort is a sorting technique
based on keys between specific ranges. It works by counting the number of objects having
distinct key values then doing some arithmetic to calculate the position of each object in the
output sequence.
Now create another array and store value in this array by getting value from UnsortedArray and find the
position of this value in CountArray and place on same position in SortedArray, after that decreasing
position by 1 in CountArray to place same value at an index smaller than this index.
SortedArray 0 1 2 3 4 5 6
1 2 3 3 5 5 7
Practical Demonstration
Example: 4.8 (Code for value range 0 to 9)
Min = Arr[0]
Max = Arr[0]
for i in range(len(Arr)):
if (Min > Arr[i]):
Min = Arr[i]
for i in range(len(Arr)):
count[Arr[i] - Min] += 1
for i in range(len(count)):
print(count[i], end=" ")
print()
for i in range(len(count)):
print(count[i], end=" ")
print()
for i in range(len(SortedArray)):
SortedArray[count[Arr[i] - Min] - 1] = Arr[i]
count[Arr[i] - Min] -= 1
for i in range(len(SortedArray)):
print(SortedArray[i], end=" ")
for i in range(len(SortedArr)):
print(SortedArr[i], end=" ")
Lab 4 Exercises:
1. What should the following array look like after applying Bubble Sort (ascending order)?
Mention the total number of swapping required and total time spend on sorting
4, 3, 9, 3, 1
2. What should the following array look like after applying Selection Sort (ascending
order)? Mention the total number of swapping required and total time spend on sorting
4, 3, 9, 3, 1
3. Q4- What should the following array look like after applying insertion sort (ascending
order)? Mention the total number of Insertion required and total time spend on sorting
4, 3, 9, 3, 1
4. Implement Bubble sorting, Selection sorting, Insertion sorting & counting sort on user
defined array. Show step by step simulation of the algorithm and compare and find the
best searching algorithm for the given value.
5. Write an algorithm that given a sequence of numbers, sorts, even numbers in ascending
order, odd numbers in descending order and places all even numbers in the initial part
of an array then odd numbers. Example: 2, 5, 1, 0, 4, 7, 9, 3, -2, 10, 20, 15 The answer is:
-2, 0, 2, 4, 10, 20, 15, 9, 7, 5, 3, 1.
LAB 5
Searching Algorithms
Not even a single day pass, when we do not have to search for something in our day to day life,
car keys, books, pen, mobile charger and what not. Same is the life of a computer, there is so
much data stored in it, that whenever a user asks for some data, computer has to search its
memory to look for the data and make it available to the user.
What if you have to write a program to search a given number in an array? How will you do it?
Well, to search an element in a given array, there are two popular algorithms available:
1. Linear Search
2. Binary Search
Linear Search
Linear search is a very basic and simple search algorithm. In Linear search, we search an
element or value in a given array by traversing the array from the starting, till the desired
element or value is found.
It compares the element to be searched with all the elements present in the array and when
the element is matched successfully, it returns the index of the element in the array, else it
return -1.
Linear Search is applied on unsorted or unordered lists, when there are fewer elements in a list.
It has a time complexity of O(n), which means the time is linearly dependent on the
number of elements, which is not bad, but not that good too.
Example: 5.1
flag = False
for i in range(len(Numbers)):
if(Numbers[i] == Number):
flag = True
break
if (flag):
print("Value Found on Index: " + str(i))
else:
print("Value Not Found in Array")
Example: 5.2
Highest = Marks[0]
Lowest = Marks[0]
Example: 5.3
Students = array([
["5111", "Furqan", "Abbsi", "0324225822", "59%"],
["5112", "Umer", "Aslam", "03472990222", "64%"],
["5119", "Asim", "Hassan", "929299292", "52%"],
["5119", "Zeeshan", "Hanif", "929929111", "75%"],
["6000", "Umair", "Iqbal", "9212038201", "87%"]
])
Index = -1
for i in range(len(Students)):
if (Students[i, 0] == ID):
Index = i
break
Binary Search
Binary Search is used with sorted array or list. In binary search, we follow the following steps:
We start by comparing the element to be searched with the element in the middle of the
list/array.
If we do not get a match, we check whether the element to be searched is less or greater than
in value than the middle element.
If the element/number to be searched is greater in value than the middle number, then we pick
the elements on the right side of the middle element (as the list/array is sorted, hence on the
right, we will have all the numbers greater than the middle number), and start again from the
step 1.
If the element/number to be searched is lesser in value than the middle number, then we pick
the elements on the left side of the middle element, and start again from the step 1.
Binary Search is useful when there are large numbers of elements in an array and they are
sorted.
So a necessary condition for Binary search to work is that the list/array should be sorted.
Some Key Point about Binary Search Algorithm
Example: 5.4
if (flag):
print("Number found on Index: " + str(Mid))
else:
print("Number Not found in array")
Example: 5.5
Example: 5.6
Students = array([
["5111", "Furqan", "Abbsi", "0324225822", "59%"],
["5112", "Umer", "Aslam", "03472990222", "64%"],
["5113", "Asim", "Hassan", "929299292", "52%"],
["5114", "Zeeshan", "Hanif", "929929111", "75%"],
["5115", "Umair", "Iqbal", "9212038201", "87%"]
])
First = 0
Last = len(Students) - 1
Mid = int((First + Last) / 2)
Index = -1
Lab 5 Exercises:
2. There is a collection of input integers and a collection of query integers. For each query
integer, determine how many times it occurs in the list of input integers.
For example, given input integers = [1, 1, 2] and queries = [1, 2, 3] we find 2 matching of
1, 1 matching of 2 and 0 matching of 3. For each query, we add an element to our return
array, results = [2,1,0]
Write a method MatchingIntegers(). The function must return an array of integers
representing the frequency of occurrence of each query integer in integers.
MatchingIntegers() has the following parameters:
integers - an array of integers to search
queries - an array of query integers
Note: Use linear search algorithm for searching.
LAB 6
Linked List
In a game of Treasure Hunt, you start by looking for the first clue. When you find it, instead of
having the treasure, it has the location of the next clue and so on. You keep following the clues
until you get to the treasure.
A linked list is a way to store a collection of elements. Like an array these can be character or
integers. Each element in a linked list is stored in the form of a node. A node is a collection of
two sub-elements or parts. A data part that stores a number, a string or any other type of data
and a next part that stores the link to the next node.
A linked list is formed when many such nodes are linked together to form a chain. Each node
points to the next node present in the order. The first node is always used as a reference to
traverse the list and is called HEAD. The last node points to NULL.
Example: 6.1
class Node:
def __init__(self, value):
self.Info = value
self.Next = None
def Print(self):
print(self.Info)
if(self.Next is not None):
self.Next.Print()
Start = Node(22)
Start.Next = Node(24)
Start.Next.Next = Node(25)
Start.Print()
class LinkedList:
def __init__(self):
self.Start = None
def Print(self):
if(self.Start == None):
print("List is Empty")
else:
self.Start.Print()
class LinkedList:
def __init__(self):
self.Start = None
def Count(self):
if (self.Start is None):
print("List is Empty")
else:
ptr = self.Start
count = 1
while(ptr.Next != None):
ptr = ptr.Next
count += 1
return count
if(ptr == None):
print(f"Value {value} Not found is List")
else:
print(f"Value {ptr.Info} found on Position {Count}")
if(ptr == None):
print(f"Value {Find} not found in List!")
else:
ptr.Info = value
print(f"Value {Find} has been changed with {ptr.Info}")
def DeleteFromEnd(self):
if (self.Start is None):
print("List is Empty")
elif (self.Start.Next is None):
self.Start = None
else:
ptr = self.Start;
while(ptr.Next.Next is not None):
ptr = ptr.Next
ptr.Next = None
def DeleteFromBegin(self):
if(self.Start is None):
print("List is Already Empty")
else:
self.Start = self.Start.Next
Lab 6 Exercises:
1. Create a Linked list and insert following values 50, 30, 8, 65, 89, 85, 7 respectively.
Apply Insertion sorting algorithm on this list to sort in Ascending Order. Print Sorting
Linked List.
2. Continue from above question create a method that take a key in parameter and find
key using binary search approach.
3. Design and implement an experiment that will compare the performance of a Python
list with a list implemented as a linked list.
LAB 7
Two-way & Circular Linked List
Example: 7.1 (Create Node Class and DoublyLinked Class and Add Print Method in DoublyLinked class)
class Node:
class DoublyLinked:
def PrintList(self):
if(self.Start == None):
print("List is Empty")
else:
ptr = self.Start
while(ptr != None):
print(ptr.Info)
ptr = ptr.Next
def DeleteFromBegin(self):
if(self.Start == None):
print("List is Already Empty")
elif (self.Start.Next == None):
self.Start = None
else:
self.Start = self.Start.Next
self.Start.Prev = None
def DeleteFromEnd(self):
if(self.Start == None):
print("List is Already Empty")
elif(self.Start.Next == None):
self.Start = None
else:
ptr = self.Start
while(ptr.Next != None):
ptr = ptr.Next
ptr.Prev.Next = None
for singly linked list, next pointer of last item points to the first item
In doubly linked list, prev pointer of first item points to last item as well.
Example: 7.6
A three-member circular singly linked list can be created as:
class Node:
One = Node(1);
two = Node(2);
three = Node(3);
One.Next = two
two.Next = three
three.Next = One
One.Print(One)
#it will run infinite Time
Lab-7 Exercises:
1. Using a linked list store different courses and their prerequisites in chain and based on
the list print all prerequisites course when user want to register any course.
User Input: AI
Print: OOAD | DBMS | Dst | OOP | PF
2. Create a data structure to store invoice. This data structure can hold M/S Name,
Company Name, Contact Number, Date, List of items (with their quantity & unit price)
and total amount of invoice.
Your program should take name, cell number first and then take items with their
quantity & Price from user and display proper invoice like below image.
________________________________________________________________________
Name: Muhammad Furqan Abbasi Date: 10-01-2020
Company: Orange Solutions Contact: 0324-2258232
________________________________________________________________________
S/no Particular Qty Rate Amount
Total: 11200
LAB 8
Stack
A Stack is a list of element in which an element may be inserted or deleted only at one end,
called the top of the stack. It is a simple data structure that allows adding and removing
elements in a particular order. Every time an element is added, it goes on the top of the stack
and the only element that can be removed is the element that is at the top of the stack.
Example: 8.1
from numpy import array
top = [-1]
MAXSTK = 5
Arr = array([0 for i in range(0, MAXSTK)])
print(Arr)
top = [-1]
MAXSTK = 5
Arr = array([0 for i in range(0, MAXSTK)])
peek() − get the top data element of the stack, without removing it.
Example: 8.3
top = [-1]
MAXSTK = 5
Arr = array([0 for i in range(0, MAXSTK)])
print(Peek(Arr, top))
1. Get TOP and MAXSTK of Stack (MAXSTK means total strength of element in Array)
2. Check the TOP is equal or not equal to MAXSTK - 1
3. If the TOP is equal to MAXSTK - 1, then print the stack is already full
Example: 8.4
def IsFull(top, MAXSTK):
if(top[0] == MAXSTK-1):
return True
else:
return False
top = [-1]
MAXSTK = 5
Arr = array([0 for i in range(0, MAXSTK)])
print(IsFull(top, MAXSTK))
Example: 8.5
def IsEmpty(top):
if(top[0] == -1):
return True
else:
return False
top = [-1]
MAXSTK = 5
Arr = array([0 for i in range(0, MAXSTK)])
print(IsEmpty(top))
Below we have a simple python program implementing stack data structure while following the
object oriented programming concepts.
Example: 8.6
from numpy import array
class Stack:
def IsFull(self):
if(self.Top == self.Size - 1):
return True
else:
return False
def IsEmpty(self):
if(self.Top == -1):
return True
else:
return False
def Pop(self):
if(self.IsEmpty()):
print("stack is Empty")
else:
Value = self.Arr[self.Top]
self.Top -= 1
return Value
def Peek(self):
if(self.Top == -1):
print("Stack is Empty")
else:
return self.Arr[self.Top]
def Len(self):
if(self.Top == -1):
print("List is Empty")
else:
return self.Top + 1
def Print(self):
if(self.Top == -1):
print("Stack is Empty")
else:
for i in range(0 , self.Top + 1):
print(self.Arr[i], end=" ")
MyStack = Stack(5)
while (True):
print();
print("1 : Push an element on the stack ");
print("2 : Pop an element from the stack ");
print("3 : Display the top element ");
print("4 : Display all elements ");
print("5 : Display size of stack ");
print("6 : Close the program ");
if (choice == 6):
break
elif(choice == 1):
print()
Item = int(input("Enter the Value to be pushed in stack: "))
MyStack.Push(Item)
elif(choice == 2):
print()
print(str(MyStack.Pop()) + " value removed from stack")
elif(choice == 3):
print()
print("Top value of stack is: " + str(MyStack.Peek()))
elif(choice == 4):
MyStack.Print()
elif(choice == 5):
print(MyStack.Len())
print("End")
Lab-8 Exercises:
1. Implement Stack by using Linked List.
4. Write a program to implement Undo Redo Functionality using stack. Your program
should working like user is typing something on screen and when he/she press Ctrl+z
then last character will be remove from screen and when he/she press again Ctrl+z then
previous character will be remove from screen and if he/she press Ctrl+y then last
removed character will display again on screen.
Note: To write this program you first need to understand that how we can detect
pressed key from user in python. I am writing C# code below for the sake of example.
ConsoleKeyInfo input = Console.ReadKey();
while (input.Key != ConsoleKey.Enter) {
if (!char.IsControl(input.KeyChar)) {
//Do some code when user press any printing character
}
else if (input.Modifiers == ConsoleModifiers.Control && input.Key ==
ConsoleKey.Z)
{
//Write some code when user press Ctrl+Z Key
}
else if (input.Modifiers == ConsoleModifiers.Control && input.Key ==
ConsoleKey.Y)
{
//Write some code when user press Ctrl+Y Key
}
else if (input.Key == ConsoleKey.Backspace) {
//Write some code when user press backspace Key
}
} //End While Loop
LAB 9
Recursion
Recursion is a programming technique in which a method makes a call to itself to solve a
particular problem. Such methods are called recursive.
Recursion is a programming technique whose correct usage leads to elegant solutions to certain
problems. Sometimes its usage could considerably simplify the programming code and its
readability.
def PrintNumber(Num):
if Num <= 10:
print(Num, end=" ")
PrintNumber(Num + 1)
PrintNumber(0)
PrintTable(2, 1, 10)
This activation record keeps the information about local variables, formal parameters, return
address and all information passed to the caller function.
def Factorial(Number):
if(Number == 1):
return 1
return Number * Factorial(Number - 1)
Factorial(5)
Power(2, 3)
def Fib(Num):
if Num == 0 or Num == 1:
return Num
return Fib(Num - 2) + Fib(Num - 1)
Tower of Hanoi
Example: 9.6
class CreateStack:
def Pop(self):
item = self.Tower[self.Top]
self.Top -= 1
return item
def Print(self):
for i in range(self.Top, -1, -1):
for j in range(i):
print(" ", end="")
print(self.Tower[i])
#Create Towers
A = CreateStack(20)
B = CreateStack(20)
C = CreateStack(20)
#Print Before
Print(A, B, C)
#Print After
Print(A, B, C)
Lab 9 Exercises:
LAB 10
Polish Notations
The way to write arithmetic expression is known as a notation. An arithmetic expression can
be written in three different but equivalent notations, i.e., without changing the essence or
output of an expression. These notations are
Infix Notation
Prefix (Polish) Notation
Postfix (Reverse-Polish) Notation
These notations are named as how they use operator in expression. We shall learn the same
here in this chapter.
Infix Notation
We write expression in infix notation, e.g. a - b + c, where operators are used in-between operands. It is
easy for us humans to read, write, and speak in infix notation but the same does not go well with
computing devices. An algorithm to process infix notation could be difficult and costly in terms of time
and space consumption.
Prefix Notation
In this notation, operator is prefixed to operands, i.e. operator is written ahead of operands. For
example, +ab. This is equivalent to its infix notation a + b. Prefix notation is also known as Polish
Notation.
Postfix Notation
This notation style is known as Reversed Polish Notation. In this notation style, the operator is postfixed
to the operands i.e., the operator is written after the operands. For example, ab+. This is equivalent to
its infix notation a + b.
The following table briefly tries to show the difference in all three notations
Infix Notation Prefix Notation Postfix Notation
Sr.No.
1 a+b +ab ab+
2 (a + b) ∗ c ∗+abc ab+c∗
3 a ∗ (b + c) ∗a+bc abc+∗
5 (a + b) ∗ (c + d) ∗+ab+cd ab+cd+∗
Parsing Expressions
As we have discussed, it is not a very efficient way to design an algorithm or program to parse
infix notations. Instead, these infix notations are first converted into either postfix or prefix
notations and then computed.
To parse any arithmetic expression, we need to take care of operator precedence and
associativity also.
Precedence
When an operand is in between two different operators, which operator will take the operand
first, is decided by the precedence of an operator over others. For example −
As multiplication operation has precedence over addition, b * c will be evaluated first. A table
of operator precedence is provided later.
Associativity
Associativity describes the rule where operators with the same precedence appear in an
expression. For example, in expression a + b − c, both + and – have the same precedence, then
which part of the expression will be evaluated first, is determined by associativity of those
operators. Here, both + and − are left associative, so the expression will be evaluated as (a + b)
− c.
Precedence and associativity determines the order of evaluation of an expression. Following is
an operator precedence and associativity table (highest to lowest) –
The above table shows the default behavior of operators. At any point of time in expression
evaluation, the order can be altered by using parenthesis. For example −
In a + b*c, the expression part b*c will be evaluated first, with multiplication as precedence
over addition. We here use parenthesis for a + b to be evaluated first, like (a + b)*c.
def IsEmpty(self):
if self.Top == -1:
return True
return False
def Pop(self):
item = self.List[self.Top]
self.Top -= 1
return item
def Peek(self):
return self.List[self.Top]
while(not stack.IsEmpty()):
item = Q[CounterQ]
CounterQ += 1
if (item != '+' and item != '-' and item != '*' and item != '/' and
item != '^' and item != '(' and item != ')'):
P += item
elif (item == '('):
stack.Push(item)
College of Computing & Information Sciences 65
Course Title: Lab-10
Data Structures & Algorithms Polish Notations
def EvaluatingOfPFN(P):
stack = CreateStack(100)
for i in range(len(P)):
Val = P[i]
if (Val != "+" and Val != "-" and Val != "*" and Val != "/" and Val != "^"):
stack.Push(Val)
else:
b = int(stack.Pop())
a = int(stack.Pop())
if Val == "+":
Result = a + b
stack.Push(Result)
elif Val == "-":
Result = a - b
stack.Push(Result)
elif Val == "*":
Result = a * b
stack.Push(Result)
elif Val == "/":
Result = a / b
stack.Push(Result)
elif Val == "^":
Result = a ^ b
stack.Push(Result)
return int(stack.Peek());
Q = Polish(InfixNot)
Result = EvaluatingOfPFN(Q)
print(Q)
print(Result)
Lab-10 Exercises:
1. Write a program to convert an INFIX expression given by the user into equivalent
POSTFIX using stack.
3. Make a calculator which will evaluate any given PREFIX or POSTFIX expression using
stack.
LAB 11
Queue
Queue is also an abstract data type or a linear data structure, just like stack data structure, in
which the first element is inserted from one end called the REAR(also called tail), and the
removal of existing element takes place from the other end called as FRONT(also called head).
This makes queue as FIFO(First in First Out) data structure, which means that element inserted
first will be removed first.
This is exactly how queue system works in real world. If you go to a ticket counter to buy movie
tickets, and are first in the queue, then you will be the first one to get the tickets. Right? Same
is the case with Queue data structure. Data inserted first, will leave the queue first.
The process to add an element into queue is called Enqueue and the process of removal of an
element from queue is called Dequeue.
Like stack, queue is also an ordered list of elements of similar data types.
Queue is a FIFO( First in First Out ) structure.
Once a new element is inserted into the Queue, all the elements inserted before the
new element in the queue must be removed, to remove the new element.
peek( ) function is oftenly used to return the value of first element without dequeuing it
Examples of Queue
Queue, as the name suggests is used whenever we need to manage any group of objects in an
order in which the first one coming in, also gets out first while the others wait for their turn, like
in the following scenarios:
Serving requests on a single shared resource, like a printer, CPU task scheduling etc.
In real life scenario, Call Center phone systems uses Queues to hold people calling them
in an order, until a service representative is free.
Handling of interrupts in real-time systems. The interrupts are handled in the same
order as they arrive i.e First come first served.
n = 5
front = 0
rear = [-1]
queue = array([0 for i in range(n)])
enQueue(queue, n, front, rear, 22)
enQueue(queue, n, front, rear, 23)
enQueue(queue, n, front, rear, 24)
enQueue(queue, n, front, rear, 25)
enQueue(queue, n, front, rear, 26)
enQueue(queue, n, front, rear, 27)
print(queue)
n = 5
front = 0
rear = [-1];
queue = array([0 for i in range(n)])
enQueue(queue, n, front, rear, 22)
enQueue(queue, n, front, rear, 23)
enQueue(queue, n, front, rear, 24)
print(queue)
deQueue(queue, n, front, rear) #out 22
deQueue(queue, n, front, rear) #out 23
Circular Queue:
Circular queue avoids the wastage of space in a regular queue implementation using arrays.
As you can see in the above image, after a bit of enqueueing and dequeueing, the size of the
queue has been reduced.
The indexes 0 and 1 can only be used after the queue is reset when all the elements have been
dequeued.
However, the check for full queue has a new additional case:
Case 1: FRONT = 0 && REAR == SIZE - 1
Case 2: FRONT == REAR + 1
The second case happens when REAR starts from 0 due to circular increment and when
its value is just 1 less than FRONT, the queue is full.
def IsFull(self):
if ((self.rear + 1) % self.size == self.front):
return True
return False
def IsEmpty(self):
if self.front == -1:
return True
return False
self.Array[self.rear] = value
def Print(self):
if(self.IsEmpty()):
print ("Queue is Empty")
elif (self.rear >= self.front):
print("Elements in the circular queue are:", end = " ")
for i in range(self.front, self.rear + 1):
print(self.Array[i], end = " ")
else:
print ("Elements in Circular Queue are:", end = " ")
for i in range(self.front, self.size):
print(self.Array[i], end = " ")
for i in range(0, self.rear + 1):
print(self.Array[i], end = " ")
def Peek(self):
return self.Array[self.front]
def Size(self):
if(self.IsEmpty()):
return 0
else:
if(self.rear >= self.front):
size = (self.rear - self.front)
else:
size = ((self.size - self.front) + self.rear)
size += 1
return size
MyQueue = Queue(5)
while (True):
print();
print("1 : Add an element on the Queue ");
print("2 : Delete an element from the Queue ");
print("3 : Display the top element ");
print("4 : Display all elements ");
print("5 : Display size of Queue ");
print("6 : Close the program ");
if (choice == 6):
break
elif(choice == 1):
print()
Item = int(input("Enter the Value to add in Queue: "))
MyQueue.enqueue(Item)
elif(choice == 2):
print()
print(str(MyQueue.dequeue()) + " value removed from Queue")
elif(choice == 3):
print()
print("Front value of Queue is: " + str(MyQueue.Peek()))
elif(choice == 4):
MyQueue.Print()
elif(choice == 5):
print(MyQueue.Size())
print("End")
Lab-11 Exercises:
1. Implement Queue using linked list with following operation, user can add, delete,
update and search data in queue.
2. Assume you have a stack with operations: push(), pop(), isEmpty(). How would you use
these stack operations to simulate a queue, in particular, the operations enqueue() and
dequeue()?
Hints: Use two stacks one of which is the main stack and one is a temporary one. You
are allowed use a while loop.
LAB 12 & 13
Binary Search Tree
A Tree is a non linear data structure containing the set of one or more data nodes where one
node is designated as the root of the tree while the remaining nodes are called as the children
of the root. The nodes other than the root node are partitioned into the non empty sets where
each one of them is to be called sub-tree. Nodes of a tree either maintain a parent-child
relationship between them or they are sister nodes. In a general tree, a node can have any
number of children nodes but it can have only a single parent.
The tree data structure can be classified into six different categories. But in this class/Lab we
only discuss Binary Search Tree.
Binary Search tree is a non linear data structure, in which the nodes are arranged in a specific
order. This is also called ordered binary tree. In a binary search tree, the value of all the nodes
in the left sub-tree is less than the value of the root. Similarly, value of all the nodes in the right
sub-tree is greater than or equal to the value of the root. This rule will be recursively applied to
all the left and right sub-trees of the root.
Try to Create a Binary Search Tree using the following value on your register
[50, 60, 55, 59, 40, 30, 20, 21, 35, 45, 47, 46]
Searching become very efficient in a binary search tree since, we get a hint at each step,
about which sub-tree contains the desired element.
The binary search tree is considered as efficient data structure in compare to arrays and
linked lists. In searching process, it removes half sub-tree at every step. Searching for an
element in a binary search tree takes O(log2n) time. In worst case, the time it takes to
search an element is 0(n).
It also speed up the insertion and deletion operations as compare to that in array and
linked list.
Example: 12.1
class TreeNode:
class BST
def __init__(self):
self.Root = None
Example: 12.2
def Insert(self, value):
if(self.Root == None):
self.Root = TreeNode(value)
else:
ptr = self.Root
while(ptr != None):
if(value < ptr.data):
if(ptr.left == None):
ptr.left = TreeNode(value)
break
else:
ptr = ptr.left
Pre-order Traversal:
In this technique, we do the following:
1. Process data of root node.
2. First, traverse left sub-tree completely.
3. Then, traverse right sub-tree.
Example: 12.3
Post-order Traversal
In this traversal technique we do the following:
Example: 12.4
In-order Traversal
In in-order traversal, we do the following:
Example: 12.5
Desc-order Traversal
In Desc-order traversal, we do the following:
Example: 12.5
Example: 13.2 (Add FindHighestValue method that return highest value of the Tree)
def FindHighestValue(self):
if self.Root is None:
print("Tree is Empty")
return None
else:
ptr = self.Root
while ptr.right is not None:
ptr = ptr.right
return ptr
Example: 13.3 (Add FindLowestValue method that return lowest value of the Tree)
def FindLowestValue(self):
if self.Root is None:
print("Tree is Empty")
return None
else:
ptr = self.Root
while ptr.left is not None:
ptr = ptr.left
return ptr
Example: 13.4
3. Write a method that can update every key in BST to contain sum of all greater keys
4. Write a program to remove nodes from BST that have keys outside the valid range.
Range should be providing by user.