Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Lab Solutions A-03

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

Lab 01 To learn the basic concepts of

Data Structure & Algorithms


1.Discuss the characteristics of Algorithms.
• Algorithm should be unambiguous (Clear)
• Number of input(s) must be finite
• Number of output(s) must be finite
• Algorithm must be unambiguous
• Algorithm should be feasible (efficient) in accordance with time and
memory
• Algorithm should be independent on any programming language
• Algorithm must be completed within a finite number of steps.

2.How do you differentiate linear and non- linear data structures, Also give some
examples of both data structures.
Linear Data Structures Non-Linear Data Structures
Each member element is connected to theNo set sequence of connecting all it’s
preceding and subsequent elements in a elements and each element can have
sequential order multiple paths to connect to other elements
Structure makes it possible to traverse in
Such data structures support multi-level
a single run and level storage and often cannot be traversed in
single run.
easy to implement Not easy to implement
computer memory is sequential for such more efficient in utilizing computer
data structures memory
Examples: Array, Stacks and Queue Example: Tree and Graphs

3. Name some commonly used abstract data types.


A. List
B. Stack
C. Queue
4. What do you understand by the term Algorithm analysis? Discuss.

Algorithm analysis is a process by which we analyze the time complexity and


space complexity of an algorithm.
This is done to figure out how efficient an algorithm is.
Time Complexity: The time an algorithm will take to run
Space Complexity: The memory space an algorithm utilizes.
a) Best Case: Minimum time/memory space taken
b) Average Case: Average amount of time/memory space taken
c) Worst Case: Maximum amount of time /memory space taken
To determine the efficiency, we focus on the worst cases mostly.

5. Identify Time Complexity and upper bound of following:

For the IF condition T(n)= C where C is a constant number


For the ELSE condition T(n)= C1n+C2
Even though there are 2 nested loops for loop ,it is only the i loop which would be
iterated for ‘n’ number of times as the break statement cease the iterations of j
loop.
Hence Time Complexity will be T(n)=T (Cn0, C1n+C2)
Since they are conditional statements ,only the maximum power of n would be
taken…
Hence ;
T(n)= C1n+C2 and Upper Bound is O(n)
The first for loop iterates for C1n times
The second loop is a nested for loop that iterates for C2 (n*m) times
The third loop is a for loop iterating for C3n times
Hence T(n)= C1n+ C2 (n*m)+ C3n
T(n)=( C1+ C3 )n + C2 (n*m)
T(n)= C1n + C2 (n*m) // C1+ C3 is still a constant
T(n)= C1n + C2 (n*m) and Upper Bound is O(n*m)
Lab 02 Array data structures
i. Insertion ii. Deletion iii. Traversing

1. Let an array named LA consist of 4 elements 2,4,6 & 8. write down the code to
traverse (or print) all elements in the array

INPUT:
#include<iostream>
using namespace std;
void Traverse(int arr[],int size)
{
cout<<"Array is [";
for (int j=0;j<size;j++)
{
cout<<arr[j];
if(j==size-1)
{
cout<<"]"<<endl;
}
else if(j>=0 and j<size-1)
{
cout<<",";
}
}
}
int main()
{
int LA[4]={2,4,6,8};
Traverse(LA,4);
return 0;
}

OUTPUT:
Array is [2,4,6,8]
2. Use insertion algorithm to add an element (Give implementation)
i. 1 at index 0
ii. 5 at index 2
iii. 3 at index 4

INPUT:
#include<iostream>
using namespace std;
void Traverse(int arr[],int size)
{
cout<<"Array is [";
for (int j=0;j<size;j++)
{
cout<<arr[j];
if(j==size-1)
{
cout<<"]"<<endl;
}
else if(j>=0 and j<size-1)
{
cout<<",";
}
}
}
void Insertion(int arr[],int& no,int InsertingPosition,int
ElementToBeInserted)
{

int j=no-1;
while(j>=InsertingPosition)
{
arr[j+1]=arr[j];
j=j-1;
}
no=no+1;
arr[InsertingPosition]=ElementToBeInserted;

}
int main()
{
char choice;
int position,element;
int LA[4]={2,4,6,8};
int size=4;

Traverse(LA,size);
cout<<"Do you want to Insert another Element in the Array?Enter Y/N:";
cin>>choice;
while(choice=='Y' || choice=='y')
{
cout<<"Enter position to be inserted(0 to "<<size-1<<"):";
cin>>position;
cout<<"Enter element to be inserted(any integer):";
cin>>element;
if(position>=0 && position<=size-1)
{
Insertion(LA,size,position,element);
Traverse(LA,size);
}
else
{
cout<<"Enter a correct integer for position to be
inserted"<<endl;
}
cout<<endl;
cout<<"Do you want to Insert another Element in the Array?Enter
Y/N:";
cin>>choice;
}
return 0;
}
OUTPUT:
Array is [2,4,6,8]
Do you want to Insert another Element in the Array?Enter Y/N:y
Enter position to be inserted(0 to 3):0
Enter element to be inserted(any integer):1
Array is [1,2,4,6,8]

Do you want to Insert another Element in the Array?Enter Y/N:y


Enter position to be inserted(0 to 4):2
Enter element to be inserted(any integer):5
Array is [1,2,5,4,6,8]

Do you want to Insert another Element in the Array?Enter Y/N:y


Enter position to be inserted(0 to 5):4
Enter element to be inserted(any integer):3
Array is [1,2,5,4,3,6,8]

Do you want to Insert another Element in the Array?Enter Y/N:n


3. If the size of the given array is 4 then calculate the Time complexity of insertion
algorithm when
i. Insert an element at the beginning of array
i. Insert an element at the end of array
ii. Insert the element in the middle of array

ALGORITHM:
1. Set j=N-1 k=index at which element
2. Repeat Steps 3 and 4 while j≥k will be inserted
3. array[j+1] =array[j] N=No of elements
4. j=j-1 ITEM=element that will be
5. array[k]=ITEM inserted
6. Set N=N+1

i)Worst Case Scenario: Insertion at the beginning of the array(k=0,N=4)


k=0 j=3 j≥k✓ statement 3 ✓ j=j-1✓
k=0 j=2 j≥k✓ statement 3 ✓ j=j-1✓
k=0 j=1 j≥k✓ statement 3 ✓ j=j-1✓
k=0 j=0 j≥k✓ statement 3 ✓ j=j-1✓
k=0 j=-1 j≥k
statement 5✓
N=N+1✓

Statement Operation Iteration Sub Total


1 2 1 2
2 1 5(N+1) 5(N+1)
3 1 4(N) 4(N)
4 2 4(N) 8(2N)
5 1 1 1
6 2 1 2
T(N)=2+(N+1)+N+2N+1+2=4N+6
T(4)=22
Upper Bound➔O(N)
ii)Best Case Scenario: Insertion at the end of the array(k=4,N=4)
k=4 j=3 j≥k
statement 5✓
N=N+1✓
Statement Operation Iteration Sub Total
1 2 1 2
2 1 0 0
3 1 0 0
4 2 0 0
5 1 1 1
6 2 1 2
T(N)=5
Lower Bound➔O(1)

ii)Average Case Scenario: Insertion at the middle of the array(k=2,N=4)


k=2 j=3 j≥k✓ statement 3 ✓ j=j-1✓
k=2 j=2 j≥k✓ statement 3 ✓ j=j-1✓
k=2 j=1 j≥k
statement 5✓
N=N+1✓
Statement Operation Iteration Sub Total
1 2 1 2
2 1 3 3
3 1 2 2
4 2 2 4
5 1 1 1
6 2 1 2
T(4)=14
Average Bound➔O(N)
4. Consider the array in question 2, Use deletion algorithm(Give implementation) to
remove an element
i. 1 at index 0
ii. 5 at index 2
iii. 3 at index 4

INPUT:
#include<iostream>
using namespace std;

void Traverse(int arr[],int size)


{
cout<<"Array is [";
for (int j=0;j<size;j++)
{
cout<<arr[j];
if(j==size-1)
{
cout<<"]"<<endl;
}
else if(j>=0 and j<size-1)
{
cout<<",";
}
}
}

void Deletion(int arr[],int& size,int DeletingPosition)


{
int j=DeletingPosition;
while(j<size-1)
{
arr[j]=arr[j+1];
j=j+1;
}
size=size-1;
}
int main()
{
int LA[7]={1,2,5,4,3,6,8};
Traverse(LA,7);
int size=7;
int position;
cout<<"Enter position to be deleted(0 to 6):";
cin>>position;
if(position>=0 && position<=size)
{
Deletion(LA,size,position);
Traverse(LA,size);
}
else
{
cout<<"Enter a correct integer for position to be deleted"<<endl;
}
return 0;
}

OUTPUT:

Array is [1,2,5,4,3,6,8]
Enter position to be deleted(0 to 6):0
Array is [2,5,4,3,6,8]

Array is [1,2,5,4,3,6,8]
Enter position to be deleted(0 to 6):2
Array is [1,2,4,3,6,8]

Array is [1,2,5,4,3,6,8]
Enter position to be deleted(0 to 6):4
Array is [1,2,5,4,6,8]
5. If the size of given array is 4 then calculate the Time complexity of deletion algorithm
when ,
i. Delete element at the beginning of array
ii. Delete element at the end of array
iii.Delete element in the middle of array

ALGORITHM:
1. Set j=k k=index at which element will
2. Repeat Steps 3 and 4 while j<N-1 be deleted
3. array[j] =array[j+1] N=No of elements
4. j=j+1
5. Set N=N-1

i)Worst Case Scenario: Deletion at the beginning of the array(k=0,N=4)


k=0 j=0 j<N-1✓ statement 3 ✓ j=j+1✓
k=0 j=1 j<N-1✓ statement 3 ✓ j=j+1✓
k=0 j=2 j<N-1✓ statement 3 ✓ j=j+1✓
k=0 j=3 j<N-1
N=N-1✓

Statement Operation Iteration Sub Total


1 1 1 1
2 1 4(N) 4(N)
3 1 3(N-1) 3(N-1)
4 2 3(N-1) 6(2N-2)
5 2 1 2
T(N)=1+N+(N-1)+ (2N-2)+2=4N
T(4)=16
Upper Bound➔O(N)
ii)Best Case Scenario: Deletion at the end of the array(k=4,N=4)
k=4 j=4 j<N-1
N=N-1✓

Statement Operation Iteration Sub Total


1 1 1 1
2 1 0 0
3 1 0 0
4 2 0 0
5 2 1 2
T(N)=3
Lower Bound➔O(1)

ii)Average Case Scenario: Deletion at the middle of the array(k=2,N=4)


k=2 j=2 j<N-1✓ statement 3 ✓ j=j+1✓
k=2 j=3 j<N-1
N=N-1✓

Statement Operation Iteration Sub Total


1 1 1 1
2 1 2 2
3 1 1 1
4 2 1 2
5 2 1 2
T(4)=8
Average Bound➔O(N)
Lab 03 Searching Algorithms
i. Linear Search ii. Binary Search

1. Assume array [ ] = {2, 4, 6, 8,}. Give implementation of Linear search algorithm


to ;
i. find element 8 in array
ii. find element 3 in array
INPUT:
#include<iostream>
using namespace std;

void LinearSearch(int arr[],int size,int ElementToBeFound)


{
int location;
arr[size]=ElementToBeFound;
location=0;
while(arr[location]!=ElementToBeFound)
{
location++;
}
if(location==size)
{
cout<<ElementToBeFound<<" does not exist in the list! "<<endl;
}
else
{
cout<<ElementToBeFound<<" found at index "<<location<<endl;
}

}
void MakeList(int NoOfElements,int (&myArray)[])//correct way to pass
array by reference
{
int Element;
myArray[NoOfElements];
for(int i=0;i<NoOfElements;i++)
{
cout<<"Enter Element at index "<<i<<" :";
cin>>Element;
myArray[i]=Element;
}
}
void TraverseList(int Size,int arr[])
{
cout<<"List is [";
for (int j=0;j<Size;j++)
{
cout<<arr[j];
if(j==Size-1)
{
cout<<"]"<<endl;
}
else if(j>=0 and j<Size-1)
{
cout<<",";
}
}

int main()
{
int ElementNumber;
cout<<"Enter the number of elements in your list:";
cin>>ElementNumber;
cout<<endl;
int A[ElementNumber];
MakeList(ElementNumber,A);
cout<<endl;
char choice;
int ITEM;
cout<<"Do you want to start searching? (Y/N)";
cin>>choice;
while(choice=='y' || choice=='Y')
{
cout<<endl;
TraverseList(ElementNumber,A);
cout<<endl<<"Which element do you want to search for?";
cin>>ITEM;
LinearSearch(A,ElementNumber,ITEM);
cout<<endl<<"Do you want to continue searching ?(Y/N)";
cin>>choice;
}
return 0;
}

OUTPUT:
Enter the number of elements in your list:4

Enter Element at index 0 :2


Enter Element at index 1 :4
Enter Element at index 2 :6
Enter Element at index 3 :8

Do you want to start searching? (Y/N)y

List is [2,4,6,8]

Which element do you want to search for?8


8 found at index 3

Do you want to continue searching ?(Y/N)Y

List is [2,4,6,8]

Which element do you want to search for?3


3 does not exist in the list!

Do you want to continue searching ?(Y/N)N


2. let assume A[]= {2,5,5,5,6,6,8,9,9,9} sorted array of integers containing
duplicates, apply binary search algorithm to Count occurrences of a number
provided, if the number is not found in the array report that as well. (Give
implementation)
For example:
Input: 5
Output: Element 5 occurs 3 times

INPUT:

#include<iostream>
#include<cmath>
using namespace std;

void BinarySearch(int size,int arr[],int ElementToBeFound)


{
int BEG,END,MID,count;
BEG=0;
END=size-1;
MID=floor((BEG+END)/2);//in case of float numbers
count=0;

while (arr[MID]!=ElementToBeFound && BEG<=END)


{
if(ElementToBeFound<arr[MID])
{
END=MID-1;
}
else
{
BEG=MID+1;
}
MID=floor((BEG+END)/2);
}
if(arr[MID]==ElementToBeFound)
{

for(int i=0;i<size;i++)
{
if(arr[i]==ElementToBeFound)
{
count++;
}
}
cout<<"Element "<<ElementToBeFound<<" occurs "<<count<<" times
"<<endl;
}
else
{
cout<<ElementToBeFound<<" is not present in the list!"<<endl;
}
}
void TraverseList(int size,int arr[])
{
cout<<"List is [ ";
for(int i=0;i<size;i++)
{
if(i==size-1)
{
cout<<arr[i]<<" ]"<<endl;
}
else
{
cout<<arr[i]<<" , ";
}
}
}
void Makelist(int size,int (&arr)[])
{
arr[size];
int element;
for(int i=0;i<size;i++)
{
cout<<"Enter element at index "<<i<<" : ";
cin>>element;
arr[i]=element;
}
}
int main()
{
int size,ITEM;
char choice;
cout<<"How many elements do you want in the list?";
cin>>size;
cout<<endl;
int A[size];
Makelist(size,A);
TraverseList(size,A);
cout<<endl;
cout<<"Do you want to start your search?";
cin>>choice;
while (choice=='y' || choice=='Y')
{
cout<<"Enter element you want to search:";
cin>>ITEM;
BinarySearch(size,A,ITEM);
cout<<endl<<"Do you want to continue your search?";
cin>>choice;
}
return 0;
}
OUTPUT:
How many elements do you want in the list?10

Enter element at index 0 : 2


Enter element at index 1 : 5
Enter element at index 2 : 5
Enter element at index 3 : 5
Enter element at index 4 : 6
Enter element at index 5 : 6
Enter element at index 6 : 8
Enter element at index 7 : 9
Enter element at index 8 : 9
Enter element at index 9 : 9
List is [ 2 , 5 , 5 , 5 , 6 , 6 , 8 , 9 , 9 , 9 ]

Do you want to start your search?y


Enter element you want to search:5
Element 5 occurs 3 times

Do you want to continue your search?Y


Enter element you want to search:9
Element 9 occurs 3 times

Do you want to continue your search?Y


Enter element you want to search:6
Element 6 occurs 2 times

Do you want to continue your search?y


Enter element you want to search:3
3 is not present in the list!

Do you want to continue your search?y


Enter element you want to search:2
Element 2 occurs 1 times

Do you want to continue your search?n


3. Compare linear & binary Search algorithms on the basis of time complexity,
which one is better in your opinion? When we preferred binary search over liner
search? Discuss.
Linear Search
ALGORITHM:
1. Set A[N]=ITEM N=Number of elements in Array/List
2. Set location=0 ITEM=Element to be found
3. Repeat step 4 while A[location]≠ITEM
4. location=location+1
5. IF location=N then
Set location= -1
6. Return location

Worst Case Scenario


Element not present in the array
E.g A = [2,4,6,8] ITEM=10 N=4
statement 1 ✓ statement 2 ✓
A [4] = 10
loc = 0 A[loc] ≠ 10✓ location=location+1✓
loc = 1 A[loc] ≠ 10✓ location=location+1✓
loc = 2 A[loc] ≠ 10✓ location=location+1✓
loc = 3 A[loc] ≠ 10✓ location=location+1✓
loc = 4 A[loc] ≠ 10 
loc==N✓ loc= -1
Return -1
Statement Operation Iteration Sub Total
1 1 1 1
2 1 1 1
3 1 N+1 N+1
4 1 N N
5 1 1 1
6 1 1 1
Hence Worst-Case Big O notation is O(N)
Best Case Scenario
Element present at index 0 in the array
E.g A = [2,4,6,8] ITEM=2 N=4
statement 1 ✓ statement 2 ✓
A [4] = 2
loc = 0 A[loc] ≠ 2 
loc==N 
Return 0

Since no iteration takes place Best-Case Big O notation is O(1)

Binary Search
ALGORITHM:
1.[Initialize segment variables]
Set BEG=0,END=N-1 and MID=INT((BEG+END)/2)
2. Repeat Steps 3 and 4 while BEG ≤ END and DATA[MID]≠ITEM
3. If ITEM<DATA[MID] then
Set END=MID-1
Else N=Number of elements in Array/List
Set BEG=MID+1 ITEM=Element to be found
4. Set MID= INT((BEG+END)/2) BEG = Beginning Index
[End of Step 2 loop] END = Ending Index
5. If DATA[MID]=ITEM then MID = Middle Index
Set loc=MID DATA=Array
Else
Set loc=NULL
[End of If Structure]
6.Return loc
Worst Case Scenario
Element not present in the array OR Element present at index N-1
T(N)=C1log(N)
Big O notation is O(logN)
Please note that the base of the log is 2 due to every iteration being divided by 2

Best Case Scenario


Element present in the middle of the array
No iterations so Big O notation is O(1) since Time Complexity will be constant

Which one is better in my opinion?


If we compare the time complexities of worst case scenarios of both searches,the
time complexity of binary search is lesser than that of linear search hence
overall,binary search is better in my opinion.
When we preferred binary search over liner search? Discuss
-When data is sorted already
-When data size is large
Lab 04 Sorting Operation in an Array
Bubble Sort Algorithm

1. Give implementation of bubble sort algorithm let’s assume Array “A” is


consisting of 6 elements which are stored in descending order.

INPUT:
#include<iostream>
using namespace std;
void BubbleSort(int arr[],int sizeOfArray)
{
int flag=0;
for(int i=0;i<sizeOfArray-1;i++)
{
for(int j=0;j<sizeOfArray-1-i;j++)
{
if (arr[j]>arr[j+1])
{
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
flag=1;
}
}
if(flag==0)
{
break;
}
}
}
void Traverse(int arr[],int size)
{
cout<<" [";
for (int j=0;j<size;j++)
{
cout<<arr[j];
if(j==size-1)
{
cout<<"]"<<endl;
}
else if(j>=0 and j<size-1)
{
cout<<",";
}
}
}
void MakeArray(int (&arr)[],int size)
{
int Element;
arr[size];
for (int i=0;i<size;i++)
{
cout<<"Enter Element at index "<<i<<" : ";
cin>>Element;
arr[i]=Element;
}
}
int main()
{
int NumberOfElements;
cout<<"Enter number of elements of array:";
cin>>NumberOfElements;

int A[NumberOfElements];
MakeArray(A,NumberOfElements);
cout<<endl<<"Original Array : ";
Traverse(A,NumberOfElements);
BubbleSort(A,NumberOfElements);
cout<<endl<<"After Sorting : ";
Traverse(A,NumberOfElements);

return 0;
}
OUTPUT:
Enter number of elements of array:6
Enter Element at index 0 : 100
Enter Element at index 1 : 80
Enter Element at index 2 : 60
Enter Element at index 3 : 40
Enter Element at index 4 : 20
Enter Element at index 5 : 10

Original Array : [100,80,60,40,20,10]

After Sorting : [10,20,40,60,80,100]


2. Re-write bubble sort algorithm for recursive function call, also analyze the
worst time complexity of recursive bubble sort algorithm.
Algorithm:
BubbleSort (arr [], endingIndex)
1. //Base Condition if array has only one element
If (endingIndex==0) then
//array already sorted
2. Repeat step 3 for i=0 to i< endingIndex
3. If (arr[i]>arr[i+1]) then
swap arr[i] and arr[i+1]
4. Call BubbleSort (arr, endingIndex-1)
Time Complexity Analaysis:
Here, n is endingIndex of array
For n==1
T(n)=1 //only one return statement
For n>1
Time complexity of for loop = 2n+1
Condition Operation Iteration Sub Total
i=0 1 1 1
i < endingIndex 1 n n
i++ 1 n-1 n-1
swapping 1 1 1

T(n)=T(n-1) + (2n+1) +1 //+1 due to n-1 operation in the call


T(n)=[T(n-2)+2n+2] + (2n+2)
T(n)=T(n-2) + 2(2n+2)
T(n)=T(n-3) + 3(2n+2)
T(n)=T(n-4) + 4(2n+2)

Generalization:
T(n)=T(n-k) + k(2n+2)
If k=n
T(n)=T(n-n) + n(2n+2)
T(n)=T(0) + 2n2+2n
T(n)= 2n2+2n
Hence Worst Case is O(n2)
INPUT:
#include<iostream>
#include<iostream>
using namespace std;
void BubbleSort_Recursive(int arr[],int endingIndex)
{
if(endingIndex==0)//if array has only one value
{
return; //do nothing
}
for(int i=0;i<endingIndex;i++)
{
if(arr[i]>arr[i+1])
{
int temp=arr[i];
arr[i]=arr[i+1];
arr[i+1]=temp;
}
}
BubbleSort_Recursive(arr,endingIndex-1);
}
void Traverse(int arr[],int SizeOfArray)
{
cout<<" [";
for(int i=0;i<SizeOfArray;i++)
{
if(i==SizeOfArray-1)
{
cout<<arr[i]<<" ]"<<endl;
}
else
{
cout<<arr[i]<<" , ";
}

}
}
void MakeArray(int (&arr)[],int size)
{
int Element;
arr[size];
for(int i=0;i<size;i++)
{
cout<<"Enter element for index "<<i<<" : ";
cin>>Element;
arr[i]=Element;
}
}

int main()
{
int size;
cout<<"Enter number of Elements in the Array:";
cin>>size;
int A[size];
MakeArray(A,size);
cout<<endl<<"Before Sorting : ";
Traverse(A,size);
BubbleSort_Recursive(A,size-1);//ending index is always one less
than size
cout<<endl<<"After Sorting : ";
Traverse(A,size);
return 0;
}

OUTPUT:
Enter number of Elements in the Array:6
Enter element for index 0 : 6
Enter element for index 1 : 7
Enter element for index 2 : 5
Enter element for index 3 : 3
Enter element for index 4 : 4
Enter element for index 5 : 9

Before Sorting : [6 , 7 , 5 , 3 , 4 , 9 ]
After Sorting : [3 , 4 , 5 , 6 , 7 , 9 ]
3. Select any other sorting algorithm and implement. Assume A[]={
9,7,5,11,12,2,14,3,10,6}
INPUT:
#include<iostream>
using namespace std;
void SelectionSort(int arr[],int size)
{
int MinimumValue,location;
for(int i=0;i<size-1;i++)
{
MinimumValue=arr[i];
location=i;
for(int j=i+1;j<size;j++)
{
if(arr[j]<MinimumValue)
{
MinimumValue=arr[j];
location=j;
}
}
//swap arr[i] and arr[location]after finding minimum value
int temp=arr[location];
arr[location]=arr[i];
arr[i]=temp;
}
}
void Traverse(int arr[],int size)
{
cout<<"[ ";
for(int i=0;i<size;i++)
{
if(i==size-1)
{
cout<<arr[i]<<" ]"<<endl;
}
else
{
cout<<arr[i]<<" , ";
}
}

}
void MakeArray(int (&arr)[],int size)
{
int Element;
arr[size];
for(int i=0;i<size;i++)
{
cout<<"Enter element for index "<<i<<" : ";
cin>>Element;
arr[i]=Element;
}
}
int main()
{
int size;
cout<<"Enter number of Elements in the Array:";
cin>>size;
int A[size];
MakeArray(A,size);
cout<<endl<<"Before Sorting : ";
Traverse(A,size);
SelectionSort(A,size);
cout<<endl<<"After Sorting : ";
Traverse(A,size);
return 0;
}
OUTPUT:
Enter number of Elements in the Array:10
Enter element for index 0 : 9
Enter element for index 1 : 7
Enter element for index 2 : 5
Enter element for index 3 : 11
Enter element for index 4 : 12
Enter element for index 5 : 2
Enter element for index 6 : 14
Enter element for index 7 : 3
Enter element for index 8 : 10
Enter element for index 9 : 6

Before Sorting : [ 9 , 7 , 5 , 11 , 12 , 2 , 14 , 3 , 10 , 6 ]

After Sorting : [ 2 , 3 , 5 , 6 , 7 , 9 , 10 , 11 , 12 , 14 ]
4. Analyze the two sorting algorithms (in 1 & 3) and determine
i) Best and Worst cases
ii)Calculate Worst and Best bounds
iii) Draw conclusion on the basis of their pros & cons.

Bubble Sort Algorithm (Modified Version):


1.Set flag =true
2. Repeat steps 3 and 5 for i=0 to i<size-1 Flag variable is to break loop in
3. Repeat step 4 for j=0 to j<size-1-i case of already sorted array
4. if arr[j]>arr[j+1]
swap arr[j] and arr[j+1] arr=Array
Set flag=false size=Size of Array
5. if (flag==true) then
break;

Selection Sort Algorithm:


1. Repeat steps 2 ,3 and 5 for i=0 to i<size-1
2. Set min=arr[i] and loc=i arr=Array
3. Repeat step 4 for j=i+1 to j<size size=Size of Array
4. if arr[j]<min then min=minimum element in array
Set min=arr[j] and loc=j loc=location of minimum
5. Swap arr[i] with arr[loc] element

i) Best and Worst cases


Best Case is when the array is already sorted
Worst Case is when the array is descending order

ii)Calculate Worst and Best bounds


BEST BOUND
For Bubble Sort,
Eg if Array is [1,2,3] n=3
Flag = true i=0 0<2✓ j=0 0<2✓ arr[j]>arr[j+1]
j=1 1<2✓ arr[j]>arr[j+1]
j=2 2<

Flag = true i loop exited!


Best case is O(n) as it goes through only one loop !
For Selection Sort,
Eg if Array is [1,2,3] n=3
i=0 0<2✓ min=1 loc=0 j=1 1 < 3 ✓ arr[j] < min 
j=2 2 < 3 ✓ arr[j] < min 
j=3 3 < 3 ✓ 

i=1 1<2✓ min=2 loc=1 j=2 2 < 3 ✓ arr[j] < min 


j=3 3 < 3 

i=2 2<2

Best Case is O(n2) as both loops work

WORST BOUND

For Bubble Sort,we will check conditions for both i and j loops hence
Worst Case would be O(n2)

For Selection Sort,we will check conditions for both i and j loops hence
Worst Case would be O(n2)

iii) Draw conclusion on the basis of their pros & cons.


Algorithm Best Case Average Case Worst Case
Selection O(n2) O(n2) O(n2)
Bubble O(n) O(n2) O(n2)

The Worst Bound for both Bubble Sort and Selection Sort is O(n2)
However, the best case for Bubble Sort is O(n) while O(n2) for Selection Sort.

Hence it is a better option to use Bubble Sort when the array/list is already sorted
In other cases , Selection Sort would be a better option as it has less number of
swaps comparative to Bubble Sort.
Lab 05 Stack Data Structure
1. Give implementations of Push & Pop Algorithms with underflow & Overflow exceptions
INPUT:
#include<bits/stdc++.h>
using namespace std;

const int SIZE=5;

class Stack
{
public:
int top;
int arr[SIZE];
Stack()//default constructor
{
top=-1;
for(int i=0;i<SIZE;i++)
{
arr[i]=0;
}
}
bool isEmpty()
{
if(top==-1)
{
return true;
}
else
{
return false;
}
}
bool isFull()
{
if(top==SIZE-1)
{
return true;
}
else
{
return false;
}
}
};
void Push(Stack& s1,int x)
{
if (s1.isFull())
{
cout<<"Stack Overflow"<<endl;
}
else
{
s1.top++;
s1.arr[s1.top]=x;
}
}
int Pop(Stack& s1)
{
if (s1.isEmpty())
{
cout<<"Stack Underflow"<<endl;
return 0;
}
else
{
int PoppedValue=s1.arr[s1.top];
s1.arr[s1.top]=0;
s1.top--;
return PoppedValue;
}
}
void Display(Stack& s1)
{
for(int i=SIZE-1;i>=0;i--)
{
cout<<" "<<s1.arr[i]<<" "<<endl;
}
}
int main()
{

Stack s1;

int option,value;
cout<<"Enter Option to Perform Operation:"<<endl;
cout<<"1.Push"<<endl;
cout<<"2.Pop"<<endl;
cout<<"3.Display"<<endl;
cout<<"4.Exit"<<endl;
cin>>option;

while(option!=4)
{
switch (option)
{
case 1:
cout<<"Push Operation Chosen"<<endl;
cout<<"Enter value to push:";
cin>>value;
Push(s1,value);
break;
case 2:
cout<<"Pop Operation Chosen"<<endl;
Pop(s1);
break;
case 3:
cout<<"Display Operation Chosen"<<endl;
Display(s1);
break;
case 4:
break;
default:
cout<<"Please Enter a valid option"<<endl;
break;
}

cout<<endl<<"Enter Option to Perform Operation:"<<endl;


cout<<"1.Push"<<endl;
cout<<"2.Pop"<<endl;
cout<<"3.Display"<<endl;
cout<<"4.Exit"<<endl;
cin>>option;

}
return 0;
}

OUTPUT:
Enter Option to Perform Operation:
1.Push
2.Pop
3.Display
4.Exit
1
Push Operation Chosen
Enter value to push:1

Enter Option to Perform Operation:


1.Push
2.Pop
3.Display
4.Exit
1
Push Operation Chosen
Enter value to push:2

Enter Option to Perform Operation:


1.Push
2.Pop
3.Display
4.Exit
1
Push Operation Chosen
Enter value to push:3

Enter Option to Perform Operation:


1.Push
2.Pop
3.Display
4.Exit
1
Push Operation Chosen
Enter value to push:4

Enter Option to Perform Operation:


1.Push
2.Pop
3.Display
4.Exit
1
Push Operation Chosen
Enter value to push:5

Enter Option to Perform Operation:


1.Push
2.Pop
3.Display
4.Exit
1
Push Operation Chosen
Enter value to push:6
Stack Overflow

Enter Option to Perform Operation:


1.Push
2.Pop
3.Display
4.Exit
3
Display Operation Chosen
5
4
3
2
1

Enter Option to Perform Operation:


1.Push
2.Pop
3.Display
4.Exit
2
Pop Operation Chosen

Enter Option to Perform Operation:


1.Push
2.Pop
3.Display
4.Exit
2
Pop Operation Chosen

Enter Option to Perform Operation:


1.Push
2.Pop
3.Display
4.Exit
3
Display Operation Chosen
0
0
3
2
1

Enter Option to Perform Operation:


1.Push
2.Pop
3.Display
4.Exit
4
2. What should be the time complexity of both algorithms (discuss in this session) in your
opinion? Discuss.
PUSH ALGORITHM:
1. If (top = = MaxStack) STACK= Name of stack
Print Overflow and Return ITEM=element that will be
2. Set top=top+1 inserted
3. Set STACK [top]=ITEM MaxStack=Maximum Index
4. Return of stack

Complexity Analysis
-IF condition followed➔ step 1 followed
Since simple return statement, constant time complexity

-ELSE condition followed➔step 2 to step 4 followed


Since simple assignment and return statements, constant time complexity

So, O(n)=O (1,1)


Hence Time Complexity is constant,O(1)

POP ALGORITHM:
1.If (top = = -1) STACK= Name of stack
Print Underflow and Return ITEM=variable storing
2. Set ITEM= STACK [top] popped value
3. Set top=top-1
4. Return

Complexity Analysis
-IF condition followed➔ step 1 followed
Since simple return statement, constant time complexity

-ELSE condition followed➔step 2 to step 4 followed


Since simple assignment and return statements, constant time complexity

So, O(n)=O (1,1)


Hence Time Complexity is constant, O (1)
3. Use Stack ADT and implement logic to get same string that was provided by user Eg.
Input= data Structure Output: data Structure
Hint: Use two stacks(Stack1 & Stack2)
INPUT:
//basically turning stack to queue
#include<bits/stdc++.h>
using namespace std;

const int SIZE=100;

class Stack
{
public:
int top;
int arr[SIZE];
Stack()
{
top=-1;
for(int i=0;i<SIZE-1;i++)
{
arr[i]=0;
}
}
bool isEmpty()
{
if(top==-1)
{
return true;
}
else
{
return false;
}
}
bool isFull()
{
if(top==SIZE-1)
{
return true;
}
else
{
return false;
}
}
void Push(int value)
{
if(isFull())
{
cout<<"Stack Overflow"<<endl;
}
else
{
top++;
arr[top]=value;
}
}
char Pop()
{
if(isEmpty())
{
cout<<"Stack Underflow"<<endl;
return 0;
}
else
{
char PoppedValue=arr[top];
arr[top]=0;
top--;
return PoppedValue;
}
}
void Display()
{
for(int i=SIZE-1;i>=0;i--)
{
cout<<" "<<arr[i]<<" "<<endl;
}
}
};
void Output(Stack&s1)
{
Stack s2;
if(s2.isEmpty())
{
while (s1.isEmpty()==false)
{
s2.Push(s1.Pop());
}
}
while(s2.isEmpty()==false)
{
cout<< s2.Pop()<<" ";
}
}

int main()
{
Stack s1,s2;
char choice,character;
cout<<"Do you want to start pushing your items?(Y/N)";
cin>>choice;
while (choice=='y' || choice=='Y')
{
cout<<"Enter character to push:";
cin>>character;
s1.Push(character);
cout<<endl<<"Do you want to continue pushing?(Y/N)";
cin>>choice;
}

cout<<"Output: ";
Output(s1);

OUTPUT:
Do you want to start pushing your items?(Y/N)Y
Enter character to push:D

Do you want to continue pushing?(Y/N)Y


Enter character to push:A

Do you want to continue pushing?(Y/N)Y


Enter character to push:T

Do you want to continue pushing?(Y/N)Y


Enter character to push:A
Do you want to continue pushing?(Y/N)Y
Enter character to push:S

Do you want to continue pushing?(Y/N)Y


Enter character to push:T

Do you want to continue pushing?(Y/N)Y


Enter character to push:R

Do you want to continue pushing?(Y/N)Y


Enter character to push:U

Do you want to continue pushing?(Y/N)Y


Enter character to push:C

Do you want to continue pushing?(Y/N)Y


Enter character to push:T

Do you want to continue pushing?(Y/N)Y


Enter character to push:U

Do you want to continue pushing?(Y/N)Y


Enter character to push:R

Do you want to continue pushing?(Y/N)Y


Enter character to push:E

Do you want to continue pushing?(Y/N)Y


Enter character to push:S

Do you want to continue pushing?(Y/N)N


Output: D A T A S T R U C T U R E S
4. Write algorithm to implement two stacks in a single array
INPUT:
#include<bits/stdc++.h>
using namespace std;
class TwoStacks
{
private:
int top1,top2;
int size;
int *arr;
public:
TwoStacks(int N)
{
size=N;
top1=-1;
top2=size;
arr= new int[size];
for(int i=0;i<size;i++)
{
arr[i]=0;
}
}
void push1(int x)
{

top1++;
if(top1==top2)
{
cout<<"Stack 1 Overflow"<<endl;
top1--;
}
else
{
arr[top1]=x;
}
}
void push2(int x)
{
top2--;
if(top1==top2)
{
cout<<"Stack 2 Overflow"<<endl;
top2++;
}
else
{
arr[top2]=x;
}
}
int pop1()
{
if(top1==-1)
{
cout<<"Stack 1 Underflow"<<endl;
return -1;
}
else
{
int poppedValue=arr[top1];
arr[top1]=0;
top1--;
return poppedValue ;
}
}
int pop2()
{
if(top2==size)
{
cout<<"Stack 2 Underflow"<<endl;
return -1;
}
else
{
int poppedValue=arr[top2];
arr[top2]=0;
top2++;
return poppedValue ;
}
}
void Display()
{
cout<<"Displaying the array...."<<endl;
for (int i=0;i<size;i++)
{
cout<<" "<<arr[i]<<" ";
}
cout<<endl;
}

};
int main()
{
int size,option,value;
cout<<"Input size of array:";
cin>>size;
TwoStacks TS(size);

do
{
cout<<"Enter an option to proceed.Enter 0 to exit"<<endl;
cout<<"1.Push in Stack 1"<<endl;
cout<<"2.Push in Stack 2"<<endl;
cout<<"3.Pop in Stack 1"<<endl;
cout<<"4.Pop in Stack 2"<<endl;
cout<<"5.Display"<<endl;
cin>>option;
switch (option)
{
case 0:
break;
case 1:
cout<<"Push in Stack 1 Operation Chosen"<<endl;
cout<<"Enter value to push:";
cin>>value;
TS.push1(value);
break;
case 2:
cout<<"Push in Stack 2 Operation Chosen"<<endl;
cout<<"Enter value to push:";
cin>>value;
TS.push2(value);
break;
case 3:
cout<<"Pop in Stack 1 Operation Chosen"<<endl;
cout<<"Popped value is "<< TS.pop1()<<endl;
break;
case 4:
cout<<"Pop in Stack 2 Operation Chosen"<<endl;
cout<<"Popped value is "<< TS.pop2()<<endl;
break;
case 5:
cout<<"Display Operation Chosen"<<endl;
TS.Display();
break;
default:
cout<<"Enter correct option"<<endl;
break;
}
cout<<endl;

} while (option!=0);
return 0;
}

OUTPUT:
Input size of array:4
Enter an option to proceed.Enter 0 to exit
1.Push in Stack 1
2.Push in Stack 2
3.Pop in Stack 1
4.Pop in Stack 2
5.Display
1
Push in Stack 1 Operation Chosen
Enter value to push:10

Enter an option to proceed.Enter 0 to exit


1.Push in Stack 1
2.Push in Stack 2
3.Pop in Stack 1
4.Pop in Stack 2
5.Display
2
Push in Stack 2 Operation Chosen
Enter value to push:20

Enter an option to proceed.Enter 0 to exit


1.Push in Stack 1
2.Push in Stack 2
3.Pop in Stack 1
4.Pop in Stack 2
5.Display
5
Display Operation Chosen
Displaying the array....
10 0 0 20

Enter an option to proceed.Enter 0 to exit


1.Push in Stack 1
2.Push in Stack 2
3.Pop in Stack 1
4.Pop in Stack 2
5.Display
2
Push in Stack 2 Operation Chosen
Enter value to push:30

Enter an option to proceed.Enter 0 to exit


1.Push in Stack 1
2.Push in Stack 2
3.Pop in Stack 1
4.Pop in Stack 2
5.Display
1
Push in Stack 1 Operation Chosen
Enter value to push:40

Enter an option to proceed.Enter 0 to exit


1.Push in Stack 1
2.Push in Stack 2
3.Pop in Stack 1
4.Pop in Stack 2
5.Display
5
Display Operation Chosen
Displaying the array....
10 40 30 20

Enter an option to proceed.Enter 0 to exit


1.Push in Stack 1
2.Push in Stack 2
3.Pop in Stack 1
4.Pop in Stack 2
5.Display
3
Pop in Stack 1 Operation Chosen
Popped value is 40

Enter an option to proceed.Enter 0 to exit


1.Push in Stack 1
2.Push in Stack 2
3.Pop in Stack 1
4.Pop in Stack 2
5.Display
5
Display Operation Chosen
Displaying the array....
10 0 30 20

Enter an option to proceed.Enter 0 to exit


1.Push in Stack 1
2.Push in Stack 2
3.Pop in Stack 1
4.Pop in Stack 2
5.Display
3
Pop in Stack 1 Operation Chosen
Popped value is 10

Enter an option to proceed.Enter 0 to exit


1.Push in Stack 1
2.Push in Stack 2
3.Pop in Stack 1
4.Pop in Stack 2
5.Display
3
Pop in Stack 1 Operation Chosen
Popped value is Stack 1 Underflow
-1

Enter an option to proceed.Enter 0 to exit


1.Push in Stack 1
2.Push in Stack 2
3.Pop in Stack 1
4.Pop in Stack 2
5.Display
5
Display Operation Chosen
Displaying the array....
0 0 30 20

Enter an option to proceed.Enter 0 to exit


1.Push in Stack 1
2.Push in Stack 2
3.Pop in Stack 1
4.Pop in Stack 2
5.Display
4
Pop in Stack 2 Operation Chosen
Popped value is 30

Enter an option to proceed.Enter 0 to exit


1.Push in Stack 1
2.Push in Stack 2
3.Pop in Stack 1
4.Pop in Stack 2
5.Display
5
Display Operation Chosen
Displaying the array....
0 0 0 20

Enter an option to proceed.Enter 0 to exit


1.Push in Stack 1
2.Push in Stack 2
3.Pop in Stack 1
4.Pop in Stack 2
5.Display
4
Pop in Stack 2 Operation Chosen
Popped value is 20

Enter an option to proceed.Enter 0 to exit


1.Push in Stack 1
2.Push in Stack 2
3.Pop in Stack 1
4.Pop in Stack 2
5.Display
4
Pop in Stack 2 Operation Chosen
Popped value is Stack 2 Underflow
-1

Enter an option to proceed.Enter 0 to exit


1.Push in Stack 1
2.Push in Stack 2
3.Pop in Stack 1
4.Pop in Stack 2
5.Display
5
Display Operation Chosen
Displaying the array....
0 0 0 0

Enter an option to proceed.Enter 0 to exit


1.Push in Stack 1
2.Push in Stack 2
3.Pop in Stack 1
4.Pop in Stack 2
5.Display
0
Lab 06 Expression Evaluation through
Stack Data Structure
i. Infix ii. Postfix iii. Prefix
1. .Solve the following postfix expressions via algorithm
i. P: 5, 6,2,+,*, 12,4,/,-
Number Symbol Scanned STACK
1 5 5
2 6 56
3 2 562
4 + 58
5 * 40
6 12 40 12
7 4 40 12 4
8 / 40 3
9 - 37

Answer : 37

ii. 2,3,^,5,2,2,^,*,12,6,/,-,+
Number Symbol Scanned STACK
1 2 2
2 3 23
3 ^ 8
4 5 85
5 2 852
6 2 8522
7 ^ 854
8 * 8 20
9 12 8 20 12
10 6 8 20 12 6
11 / 8 20 2
12 - 8 18
13 + 26

Answer : 26
2.Implement the algorithm to convert the following infix expression to equivalent
postfix form.
INPUT:
#include<bits/stdc++.h>
using namespace std;
bool isOperator(char CharacterEncountered)
{
if(CharacterEncountered=='+'||CharacterEncountered=='-
'||CharacterEncountered=='*'||CharacterEncountered=='/'||CharacterEnco
untered=='^')
{
return true;
}
else
{
return false;
}
}
int Precedence(char CharacterEncountered)
{
if(CharacterEncountered=='^')
{
return 3;//highest precedence
}
else if (CharacterEncountered=='*'||CharacterEncountered=='/')
{
return 2; //second highest precedence
}
else if(CharacterEncountered=='+'||CharacterEncountered=='-')
{
return 1;//lowest precedence
}
else
{
return -1;//for opening and closing bracket
}
}
string ConvertInfixToPostfix(stack<char> STACK,string infix)
{
string postfix;
for(int i=0;i<infix.length();i++)
{
if((infix[i]>='a'&& infix[i]<='z')||(infix[i]>='A'&&
infix[i]<='Z'))
{
postfix+=infix[i];
}
else if(infix[i]=='(')
{
STACK.push(infix[i]);
}
else if(infix[i]==')')
{
while((STACK.top()!='(')&&(!STACK.empty()))
{
char temp=STACK.top();
postfix+=temp;
STACK.pop();
}
if(STACK.top()=='(')
{
STACK.pop();
}
}
else if(isOperator(infix[i]))//you can also use else block
{
if(STACK.empty())//if no operators present
{
STACK.push(infix[i]);
}
else //precendence rule
{
if(Precedence(infix[i])>Precedence(STACK.top()))
{
STACK.push(infix[i]);
}
else
if((Precedence(infix[i])==Precedence(STACK.top()))&& (infix[i]=='^'))
{
STACK.push(infix[i]);
}
else
{
while((!STACK.empty())&&
(Precedence(infix[i])<=Precedence(STACK.top())))
{
char temp=STACK.top();
postfix+=temp;
STACK.pop();
}
STACK.push(infix[i]);
}
}
}
}
while (!STACK.empty())
{
postfix+=STACK.top();
STACK.pop();
}
return postfix;
}
int main()
{
string InfixExpression,PostfixExpression;
cout<<"Enter an Infix Expression:";
cin>>InfixExpression;
stack<char> stack;
PostfixExpression=ConvertInfixToPostfix(stack,InfixExpression);
cout<<endl<<"POSTFIX EXPRESSION:"<<PostfixExpression;
return 0;
}
OUTPUT:
Enter an Infix Expression:(A+(B*C-(D/E^F)*G)*H)
POSTFIX EXPRESSION:ABC*DEF^/G*-H*+
3.Implement Infix to Postfix Conversion algorithm to solve 2,3,^,5,2,2,^,*,12,6,/,-
,+ also discuss its worst bound.
ALGORITHM:
1. Add a “)” at the end of expression P
2. Scan Expression P from left to right and repeat steps 2 and 3 until “)” is
encountered
3. IF an operand is encountered, push it onto the STACK.
4. IF an operator Θ is encountered
a) pop two operands from the STACK ,A is the top element and B is the
next to top element
b) Evaluate A Θ B
c) Place result of b on top STACK
5.Return value on top of the STACK

WORST BOUND:
Only 1 loop to scan expression so worst case is O(n).
Where n is the number of elements in expression P.

INPUT:
#include<bits/stdc++.h>
using namespace std;
bool isOperator(char CharacterEncountered)
{
if(CharacterEncountered=='+'||CharacterEncountered=='-
'||CharacterEncountered=='*'||CharacterEncountered=='/'||CharacterEnco
untered=='^')
{
return true;
}
else
{
return false;
}
}
int SolvingPostfix(string PostfixExpression)
{
stack<int> STACK;
for(int i=0;i<PostfixExpression.length();i++)
{
if(PostfixExpression[i]==',')
{
continue;
}
else
if((PostfixExpression[i]>='0')&&(PostfixExpression[i]<='9'))
{
string DoubleDigit="";
int ITEM;
if((PostfixExpression[i+1]=='0')&&(PostfixExpression[i+1]<
='9'))
{
DoubleDigit+=PostfixExpression[i];
DoubleDigit+=PostfixExpression[i+1];
i+=1;
}
else
{
DoubleDigit+=PostfixExpression[i];
}
ITEM=stoi(DoubleDigit);
STACK.push(ITEM);
}
else if(isOperator(PostfixExpression[i]))//element is an
operator
{
int operand2=STACK.top();
STACK.pop();
int operand1=STACK.top();
STACK.pop();
switch (PostfixExpression[i])
{
case '+':
STACK.push(operand1+operand2);
break;
case '-':
STACK.push(operand1-operand2);
break;
case '*':
STACK.push(operand1*operand2);
break;
case '/':
STACK.push(operand1/operand2);
break;
case '^':
STACK.push(pow(operand1,operand2));
break;
}

}
}
return STACK.top();
}
int main()
{
string postfix="2,3,^,5,2,2,^,*,12,6,/,-,+";
int solution=SolvingPostfix(postfix);
cout<<solution<<endl;
return 0;
}

OUTPUT:
26
4.Write algorithm to solve prefix expression also give implementation.
ALGORITHM:
1. Add a “(” at the beginning of expression P
2. Scan Expression P from left to right and repeat steps 2 and 3 until “(” is
encountered
3. IF an operand is encountered, push it onto the STACK.
4. IF an operator Θ is encountered
a) pop two operands from the STACK,A is the top element and B is the
next to top element
b) Evaluate A Θ B
c) Place result of b on top STACK
5.Return value on top of the STACK

INPUT:
#include<bits/stdc++.h>
using namespace std;

int SolvingPrefix(string PrefixExpression)


{
stack<int>STACK;
for(int i=PrefixExpression.length()-1;i>=0;i--)
{
if((PrefixExpression[i]>='0') && (PrefixExpression[i]<='9'
))//operand
{
STACK.push(PrefixExpression[i]-'0');
}
else//operator
{
int operand1=STACK.top();
STACK.pop();
int operand2=STACK.top();
STACK.pop();

switch (PrefixExpression[i])
{
case '+':
STACK.push(operand1+operand2);
break;
case '-':
STACK.push(operand1-operand2);
break;
case '*':
STACK.push(operand1*operand2);
break;
case '/':
STACK.push(operand1/operand2);
break;
case '^':
STACK.push(pow(operand1,operand2));
break;
}

}
}
return STACK.top();
}
int main()
{
string prefix;
cout<<"Enter expression in prefix form to evaluate :";
cin>>prefix;
int Solution=SolvingPrefix(prefix);
cout<<Solution<<endl;
return 0;
}

OUTPUT:
Enter expression in prefix form to evaluate : -+7*45+20
25
Lab 07 Queue Data Structure
1.Write Algorithms for Enqueue and dequeue operations in a circular queue, also
implement using an array.
ENQUEUE ALGORITHM:
1.IF ((front==0 and rear==SIZE-1) or(front=rear+1)) then
Write Overflow and Return
2.IF (front== -1) then
Set front=0 and rear=0;
3.ELSE IF (rear=SIZE-1) then
Set rear = 0
4. ELSE
Set rear = rear+1
5.Queue[rear]=ITEM

DEQUEUE ALGORITHM:
1.IF (front== -1) then
Write Underflow and Return
2.Set ITEM=Queue[front]
3.IF (front==rear) then
Set front = -1 and rear = -1;
4.ELSE IF (front==SIZE-1) then
Set front = 0
5. ELSE
Set front=front+1
INPUT:
#include<bits/stdc++.h>
using namespace std;
const int SIZE=3;
int Queue[SIZE];
int front=-1 ;
int rear=-1;
void Enqueue(int ElementToBeInserted)
{
if((front == 0 && rear == SIZE-1) || (front == rear+1))
{
cout<< " Queue Overflow "<<endl;
return;
}
if (front == -1)
{
front = 0;
rear = 0;
}
else
{
if (rear == SIZE- 1)
{
rear = 0;
}
else
{
rear = rear + 1;
}
}
Queue[rear] = ElementToBeInserted ;

}
void Dequeue()
{
if(front==-1)
{
cout<< " Queue Underflow "<<endl;
return;
}
Queue[front]=0;
if(front == rear)
{
front=-1;
rear=-1;
}
else
{
if(front==SIZE-1)
{
front=0;
}
else
{
front=front+1;
}
}
}
void Display()
{
for(int i=0;i<SIZE;i++)
{
cout<<" "<<Queue[i]<<" ";
}
}
int main()
{

int option,value;

cout<<"Enter Option to Perform Operation:"<<endl;


cout<<"1.Enqueue"<<endl;
cout<<"2.Dequeue"<<endl;
cout<<"3.Display"<<endl;
cout<<"4.Exit"<<endl;
cin>>option;
while(option!=4)
{
switch (option)
{
case 1:
cout<<"Enqueue Operation Chosen"<<endl;
cout<<"Enter value to insert:";
cin>>value;
Enqueue(value);
break;
case 2:
cout<<"Dequeue Operation Chosen"<<endl;
Dequeue();
break;
case 3:
cout<<"Display Operation Chosen"<<endl;
Display();
break;
case 4:
break;
default:
cout<<"Please Enter a valid option"<<endl;
break;
}

cout<<endl<<"Enter Option to Perform Operation:"<<endl;


cout<<"1.Enqueue"<<endl;
cout<<"2.Dequeue"<<endl;
cout<<"3.Display"<<endl;
cout<<"4.Exit"<<endl;
cin>>option;
}
return 0;
}
OUTPUT:
Enter Option to Perform Operation:
1.Enqueue
2.Dequeue
3.Display
4.Exit
1
Enqueue Operation Chosen
Enter value to insert:1

Enter Option to Perform Operation:


1.Enqueue
2.Dequeue
3.Display
4.Exit
1
Enqueue Operation Chosen
Enter value to insert:2

Enter Option to Perform Operation:


1.Enqueue
2.Dequeue
3.Display
4.Exit
1
Enqueue Operation Chosen
Enter value to insert:3

Enter Option to Perform Operation:


1.Enqueue
2.Dequeue
3.Display
4.Exit
3
Display Operation Chosen
1 2 3
Enter Option to Perform Operation:
1.Enqueue
2.Dequeue
3.Display
4.Exit
2
Dequeue Operation Chosen

Enter Option to Perform Operation:


1.Enqueue
2.Dequeue
3.Display
4.Exit
3
Display Operation Chosen
0 2 3
Enter Option to Perform Operation:
1.Enqueue
2.Dequeue
3.Display
4.Exit
2
Dequeue Operation Chosen

Enter Option to Perform Operation:


1.Enqueue
2.Dequeue
3.Display
4.Exit
2
Dequeue Operation Chosen

Enter Option to Perform Operation:


1.Enqueue
2.Dequeue
3.Display
4.Exit
2
Dequeue Operation Chosen
Queue Underflow

Enter Option to Perform Operation:


1.Enqueue
2.Dequeue
3.Display
4.Exit
3
Display Operation Chosen
0 0 0
Enter Option to Perform Operation:
1.Enqueue
2.Dequeue
3.Display
4.Exit
4
2. Use Queue ADT and implement 1 using built in queue functions.

INPUT:
#include<bits/stdc++.h>
using namespace std;
class CircularQueue
{
public:
int*array;
int front,rear,size;
CircularQueue(int N)//constructor
{
size=N;
front = -1;
rear = -1;
array = new int[size];
for(int i=0;i<size;i++)
{
array[i]=0;
}
}
void Enqueue(int ElementToBeInserted)
{
if((front == 0 && rear == size-1) || (front == rear+1))
{
cout<< " Queue Overflow "<<endl;
return;
}
if (front == -1)
{
front = 0;
rear = 0;
}
else
{
if (rear == size- 1)
{
rear = 0;
}
else
{
rear = rear + 1;
}
}
array[rear] = ElementToBeInserted ;
}
void Dequeue()
{
if(front==-1)
{
cout<< " Queue Underflow "<<endl;
return;
}
array[front]=0;
if(front == rear)
{
front=-1;
rear=-1;
}
else
{
if(front==size-1)
{
front=0;
}
else
{
front=front+1;
}
}
}
void Display()
{
for(int i=0;i<size;i++)
{
cout<<" "<<array[i]<<" ";
}
}
};
int main()
{
int NUMBER,option,value;
cout<<"Enter size of Queue:";
cin>>NUMBER;
CircularQueue q1(NUMBER);

cout<<"Enter Option to Perform Operation:"<<endl;


cout<<"1.Enqueue"<<endl;
cout<<"2.Dequeue"<<endl;
cout<<"3.Display"<<endl;
cout<<"4.Exit"<<endl;
cin>>option;

while(option!=4)
{
switch (option)
{
case 1:
cout<<"Enqueue Operation Chosen"<<endl;
cout<<"Enter value to insert:";
cin>>value;
q1.Enqueue(value);
break;
case 2:
cout<<"Dequeue Operation Chosen"<<endl;
q1.Dequeue();
break;
case 3:
cout<<"Display Operation Chosen"<<endl;
q1.Display();
break;
case 4:
break;
default:
cout<<"Please Enter a valid option"<<endl;
break;
}
cout<<endl<<"Enter Option to Perform Operation:"<<endl;
cout<<"1.Enqueue"<<endl;
cout<<"2.Dequeue"<<endl;
cout<<"3.Display"<<endl;
cout<<"4.Exit"<<endl;
cin>>option;
}
return 0;
}

OUTPUT:
Enter size of Queue:3
Enter Option to Perform Operation:
1.Enqueue
2.Dequeue
3.Display
4.Exit
1
Enqueue Operation Chosen
Enter value to insert:1

Enter Option to Perform Operation:


1.Enqueue
2.Dequeue
3.Display
4.Exit
1
Enqueue Operation Chosen
Enter value to insert:2

Enter Option to Perform Operation:


1.Enqueue
2.Dequeue
3.Display
4.Exit
1
Enqueue Operation Chosen
Enter value to insert:3

Enter Option to Perform Operation:


1.Enqueue
2.Dequeue
3.Display
4.Exit
1
Enqueue Operation Chosen
Enter value to insert:4
Queue Overflow

Enter Option to Perform Operation:


1.Enqueue
2.Dequeue
3.Display
4.Exit
3
Display Operation Chosen
1 2 3
Enter Option to Perform Operation:
1.Enqueue
2.Dequeue
3.Display
4.Exit
2
Dequeue Operation Chosen

Enter Option to Perform Operation:


1.Enqueue
2.Dequeue
3.Display
4.Exit
3
Display Operation Chosen
0 2 3
Enter Option to Perform Operation:
1.Enqueue
2.Dequeue
3.Display
4.Exit
1
Enqueue Operation Chosen
Enter value to insert:4

Enter Option to Perform Operation:


1.Enqueue
2.Dequeue
3.Display
4.Exit
3
Display Operation Chosen
4 2 3
Enter Option to Perform Operation:
1.Enqueue
2.Dequeue
3.Display
4.Exit
2
Dequeue Operation Chosen

Enter Option to Perform Operation:


1.Enqueue
2.Dequeue
3.Display
4.Exit
3
Display Operation Chosen
4 0 3
Enter Option to Perform Operation:
1.Enqueue
2.Dequeue
3.Display
4.Exit
4

3. Analyze circular queue {Enqueue & Dequeue} algorithms and identify Worst
time complexity with brief justification
(Algorithms written in Q1)
ENQUEUE ALGORITHM:
Worst Time for Enqueue Algorithm is O(1)
Because all conditional statements contain simple assignment statements with
constant time.
DEQUEUE ALGORITHM:
Worst Time for Dequeue Algorithm is O(1)
Because all conditional statements contain simple assignment statements with
constant time.
Lab 08 Recursive Algorithms
(Recursion)
1.Calculate the Time complexity of Fibonacci and factorial recursive algorithms,
Discuss their upper bound of both algorithms. Also give the implementation.
FIBONACCI ALGORITHM
Fib(N)
If (N<= 1) then
Return 1
ELSE
Return Fib(N-1)+Fib(N-2)

Time Complexity
Base Case is for N<=1 for which T(N) = 1 as one return statement
For the ELSE part……
T(N) = T(N-1) + T(N-2)+4
//because function is called with N-1 and N-2 as parameter
//4 because there is 1 return statement and three binary operations (+ , - and -)

Since T(N-1) takes more time ,we assume….


T(N) = T(N-1) + T(N-1)+C
T(N) = 2T(N-1) + C

T(N) =2 [2T(N-2) +C] +C


T(N) = 4T(N-2) + 3C

T(N) = 4[2T(N-3) + C]+3C


T(N) = 8T(N-3) + 7C

T(N) = 8[2T(N-4) + C]+7C


T(N) = 16T(N-4) + 15C

Generalization
T(N) = 2k T(N-k) + (2k-1)C

End to the recursive cycle is when k=N


T(N) = 2N T(N-N) + (2N-1)C
T(N) = 2N T(0) + (2N-1)C

T(0) is base case as N is lesser than 1


T(N) = 2N (1) + (2N-1)C
T(N) = 2N + (2N-1)C

Hence Worst Case is O(2N)

INPUT:
#include<bits/stdc++.h>
using namespace std;
int Fibonacci(int Number)
{
if(Number<=1)
{
return 1;
}
else
{
return Fibonacci(Number-1)+Fibonacci(Number-2);
}
}
int main()
{
int n,fib;
cout<<"Enter number to generate the Nth Fibonacci Number:";
cin>>n;
fib=Fibonacci(n);
cout<<n<<"th Fibonacci Number : "<<fib;
return 0;
}

OUTPUT:
Enter number to generate the Nth Fibonacci Number:10
10th Fibonacci Number : 89
FACTORIAL ALGORITHM
Factorial(N)
If (N==0) then
Return 1
ELSE
Return N*Factorial(N-1)

Time Complexity

Base Case is for N=0 for which T(N) = 1 as one return statement
For the ELSE part……
T(N) = T(N-1)+3 //because function is called with N-1 as parameter
//3 because there is 1 return statement and two binary
// operations (+ and *)
T(N) = [T(N-2) +3] +3
T(N) = T(N-2) + 6

T(N) = [T(N-3) + 3]+6


T(N) = T(N-3) + 9

T(N) = [T(N-4) + 3]+9


T(N) = T(N-4) + 12

Generalization
T(N) = T(N-k) + 3k

End to the recursive cycle is when k=N


T(N)= T(N-N) + 3N
T(N)= T(0) + 3N

T(0) is base case


T(N)= 1+ 3N
Hence Worst Case is O(N)
INPUT:
#include<bits/stdc++.h>
using namespace std;
int Factorial(int Number)
{
if(Number==0)
{
return 1;
}
else
{
return Number*Factorial(Number-1);
}
}

int main()
{
int n,fact;
cout<<"Enter number to calculate Factorial of :";
cin>>n;
fact=Factorial(n);
cout<<"Factorial of "<<n<<" : "<<fact;
return 0;
}

OUTPUT:
Enter number to calculate Factorial of :4
Factorial of 4 : 24
2. Write iterative factorial and Fibonacci algorithms, also analyze the time
complexity.
FACTORIAL ALGORITHM:
Factorial(N)
1.If N==0 then
Return 1
2.Else
Set fact=1
For i=1 to i=N
fact=fact*i
Return fact

Time Complexity:

Time complexity for IF case is 2 (Condition + return statement)


Time Complexity for ELSE case is 3N+1
{ i<=N condition checked N-1 times, i incremented N times, “fact=fact*i”
statement done N times and 1 return statement and 1 initializing statement }

Hence Worst case is O(N)


Implementation
#include<bits/stdc++.h>
using namespace std;
int Factorial(int Number)
{
if(Number==0)
{
return 1;
}
else
{
int fact=1;
for(int i=1;i<=Number;i++)
{
fact=fact*i;
}
return fact;
}
}
int main()
{
int n,fact;
cout<<"Enter number to calculate Factorial of :";
cin>>n;
fact=Factorial(n);
cout<<"Factorial of "<<n<<" : "<<fact;
return 0;
}

FIBONACCI ALGORITHM:
Fibonacci(N)
1.If N==1 then
Return 0
2. If N==2 then
Return 1
3.Set PreviousPreviousNumber = 0
4.Set PreviousNumber = 1
5. For i=1 to i=N
Set CurrentNumber = PreviousPreviousNumber + PreviousNumber
Set PreviousPreviousNumber = PreviousNumber
Set PreviousNumber = CurrentNumber
6.Return CurrentNumber

Time Complexity:

If condition
For N==1 time complexity is 2(Condition + return statement)
If condition
For N==2 time complexity is 2(Condition + return statement)
Else Condition
Statement 3 and Statement 4 have constant time complexities as they are simple
assignment statements
Statement 5 has a loop that runs for N times
Statement 6 has a simple return statement
Statement Operation Iteration Sub Total
3 1 1 1
4 1 1 1
5a(i<=N) 1 N-1 N-1
5b(i++) 1 N N
5c( 3 assignment statements) 3 N 3N
6 1 1 1
So time complexity is 5N+2
Worst Case is O(N)

Implementation
#include<bits/stdc++.h>
using namespace std;
int Fibonacci(int Number)
{
if (Number == 1) return 0;
if (Number== 2) return 1;
int prevPrev = 0;
int prev = 1;
int currentNumber;
for (int i = 1; i <= Number; i++) {
currentNumber = prevPrev + prev;
prevPrev = prev;
prev = currentNumber;
}
return currentNumber;
}
int main()
{
int n,fib;
cout<<"Enter number to generate the Nth Fibonacci Number:";
cin>>n;
fib=Fibonacci(n);
cout<<n<<"th Fibonacci Number : "<<fib;
return 0;
}
3.Write recursive algorithm for Tower of Hanoi Puzzle also calculate its upper
bound (also give implementation).
TOWER OF HANOI ALGORITHM
TOWER(N,BEG,AUX,END)
1.IF N=1 then
a) Write: BEG➔END
b) Return
2. ELSE
a) Call TOWER (N-1, BEG, END, AUX)
b) Write: BEG➔END
c) Call TOWER (N-1, AUX, BEG, END)

Time Complexity
Base Case is for N=1 for which T(N) = 2 as one return statement and one print
statement
For the ELSE part……

T(N) =2T(N-1)+1 //because function is called with N-1 as parameter two times
//1 because there is 1 print statement
T(N) = 2[2T(N-1) +1] +1
T(N) = 4T(N-2) + 2+1

T(N) = 4[2T(N-3) + 1]+3


T(N) = 8T(N-3) + 22+2+1

T(N) = 8[2T(N-4) + 1]+7


T(N) = 16T(N-4) + 23 +22+2+1

Generalization
T(N) = 2k T(N-k) + (2k-1+2k-2 +2k-3+……..2+1)

T(1)=1
N-k should be equal to 1
So at k=N-1 recursive cycle ends
T(N) = 2N-1 T(N-(N-1)) + (2N-2+2N-3 +2N-4+……..2+1)
T(N) = 2N-1 T(1) + (2N-2+2N-3 +2N-4+……..2+1)
T(N) = 2N-1 + 2N-2+2N-3 +2N-4+……..2+1➔EQ 1
2T(N) = 2N + 2N-1+2N-2 +2N-3+……..2+1➔EQ 2

Subtract EQ1 from EQ 2


And you get....
T(N)= 2N – 1
Hence O(2N)
INPUT:
#include<iostream>
using namespace std;
void TOWER(int N,char BEG,char AUX,char END)
{
if(N==1)
{
cout<<"Move top disk from "<<BEG<<" to "<<END<<endl;
}
else
{
TOWER(N-1,BEG,END,AUX);
cout<<"Move top disk from "<<BEG<<" to "<<END<<endl;
TOWER(N-1,AUX,BEG,END);
}

}
int main()
{
int pegs;
cout<<"Enter Number of pegs:";
cin>>pegs;
cout<<"Moving "<<pegs<<" pegs from Tower A to Tower C"<<endl;
TOWER(pegs,'A','B','C');
return 0;
}
OUTPUT:
Enter Number of pegs:3
Moving 3 pegs from Tower A to Tower C
Move top disk from A to C
Move top disk from A to B
Move top disk from C to B
Move top disk from A to C
Move top disk from B to A
Move top disk from B to C
Move top disk from A to C

4. Rewrite above algorithm using iterative logic calculate its time complexity.
ALGORITHM
1.Calculate the total number of moves required (pow(2,n)-1) where n is number of
disks
2.If number of disks (n) is even then interchange END pole and AUX pole
3.ELSE For i=1 to i=N repeat steps 4 to 6
4. IF (i%3==1)
Legal movement of top disk between BEG and END pole
5. IF (i%3==2)
Legal movement of top disk between BEG and AUX pole
6. IF (i%3==0)
Legal movement of top disk between AUX and END pole

Time Complexity
Worst Case is O(2N)
Implementation
#include<bits/stdc++.h>
using namespace std;
class Stack
{
unsigned size;
int top;
int* array;
public:
Stack(unsigned N)
{
size=N;
top=-1;
for(int i=0;i<size;i++)
{
array[i]=0;
}
}
bool isEmpty()
{
if (top==-1)
{
return true;
}
else
{
return false;
}
}
bool isFull()
{
if(top==size-1)
{
return true;
}
else
{
return false;
}
}
void push(int val)
{
if(isFull())
{
return;
}
else
{
top++;
array[top]=val;
}
}
int pop()
{
if(isEmpty())
{
cout<<"Stack Underflow"<<endl;
return 0;
}
else
{
int popValue=array[top];
array[top]=0;
top--;
return popValue;
}
}
};
void moveDisk(char fromPeg,char toPeg)
{
cout<<"Move top disk from "<<fromPeg<<" to "<<toPeg<<endl;
}
void LegalMovement(Stack BEG,Stack END,char beg,char end)
{
int pole1TopDisk=BEG.pop();
int pole2TopDisk=END.pop();

//when pole 1 is empty


if(pole1TopDisk==INT_MIN)//Minimum value for a variable of type
int
{
BEG.push(pole2TopDisk);
moveDisk(end,beg);
}
//when pole 2 is empty
if(pole2TopDisk==INT_MIN)//Minimum value for a variable of type
int
{
END.push(pole1TopDisk);
moveDisk(beg,end);
}
// When top disk of pole1 > top disk of pole2
else if (pole1TopDisk > pole2TopDisk)
{
BEG.push(pole1TopDisk);
BEG.push(pole2TopDisk);
moveDisk(end,beg);
}
// When top disk of pole1 < top disk of pole2
else
{
END.push(pole2TopDisk);
END.push(pole1TopDisk);
moveDisk(beg,end);
}
}

void IterativeTOH(int NumberOfDisks,Stack BEG,Stack AUX,Stack END)


{
int i,TotalMoves;
char Beg='A',Aux='B',End='C';
//If number of disks is even, then interchange
//destination pole and auxiliary pole
if (NumberOfDisks % 2 == 0)
{
char temp = End;
End = Aux;
Aux = temp;
}
TotalMoves=pow(2,NumberOfDisks)-1;
//Larger disks will be pushed first
for (i = NumberOfDisks; i >= 1; i--)
{
BEG.push(i);
}
for (i = 1; i <= NumberOfDisks; i++)
{
if (i % 3 == 1)
LegalMovement(BEG, END, Beg, End);

else if (i % 3 == 2)
LegalMovement(BEG, AUX, Beg, Aux);

else if (i % 3 == 0)
LegalMovement(BEG, END, Aux, End);
}
}
int main()
{
int pegs;
cout<<"Enter Number of pegs:";
cin>>pegs;
Stack BEG(pegs),END(pegs),AUX(pegs);

IterativeTOH(pegs,BEG,AUX,END);
Return 0;
}

OUTPUT:
Enter Number of pegs:3
Move top disk from A to C
Move top disk from A to B
Move top disk from C to B
Move top disk from A to C
Move top disk from B to A
Move top disk from B to C
Move top disk from A to C
Lab 09 Tree data structure
1. Construct a binary tree (initially empty) , insert nodes 15,10,20,25,8,12 with the
help of following definition of Node in BST
Struct BSTNode{
Int data;
BSTNode* left;
BSTNode* right; } BSTNode* rootPtr;
INPUT:
#include<bits/stdc++.h>
using namespace std;
struct BSTNode
{
int data;
BSTNode* left;
BSTNode* right;
BSTNode(int val)
{
data=val;
left=NULL;
right=NULL;
}
};
BSTNode* Insert(BSTNode* root,int val)
{
if(root==NULL)
{
return new BSTNode(val);
}
else if(val<root->data)
{
root->left=Insert(root->left,val);
}
else
{
root->right=Insert(root->right,val);
}
return root;
}
void inorder(BSTNode *root)
{
if(root==NULL)
{
return;
}
inorder(root->left);
cout<<root->data<<" ";
inorder(root->right);
}

int main()
{
BSTNode* rootPtr=NULL;
rootPtr=Insert(rootPtr,15);
rootPtr=Insert(rootPtr,10);
rootPtr=Insert(rootPtr,20);
rootPtr=Insert(rootPtr,25);
rootPtr=Insert(rootPtr,8);
rootPtr=Insert(rootPtr,12);

inorder(rootPtr);
cout<<endl;
return 0;
}

OUTPUT:
8 10 12 15 20 25
2. Delete One left-child-node and one right-child- node from above tree. Analyze
the change occur in the tree after deletion.
INPUT:
#include<bits/stdc++.h>
using namespace std;
struct BSTNode
{
int data;
BSTNode* left;
BSTNode* right;
BSTNode(int val)
{
data=val;
left=NULL;
right=NULL;
}
};
BSTNode* Insert(BSTNode* root,int val)
{
if(root==NULL)
{
return new BSTNode(val);
}
else if(val<root->data)
{
root->left=Insert(root->left,val);
}
else
{
root->right=Insert(root->right,val);
}
return root;
}
BSTNode* InorderSuccessor(BSTNode* root)
{
BSTNode* current=root;
while(current && current->left!=NULL)
{
current=current->left;
}
return current;
}
BSTNode* Delete(BSTNode* root,int key)
{
if(key<root->data)
{
root->left=Delete(root->left,key) ;
}
else if(key>root->data)
{
root->right=Delete(root->right,key) ;
}
else
{
//case 1 and case 2
if(root->left==NULL)
{
BSTNode* temp=root->right;
free(root);
return temp;
}
else if(root->right==NULL)
{
BSTNode* temp=root->left;
free(root);
return temp;
}
//case 3
BSTNode* temp=InorderSuccessor(root->right);
root->data=temp->data;
root->right=Delete(root->right,temp->data);
}
return root;

}
void inorder(BSTNode *root)
{
if(root==NULL)
{
return;
}
inorder(root->left);
cout<<root->data<<" ";
inorder(root->right);
}

int main()
{
BSTNode* rootPtr=NULL;
rootPtr=Insert(rootPtr,15);
rootPtr=Insert(rootPtr,10);
rootPtr=Insert(rootPtr,20);
rootPtr=Insert(rootPtr,25);
rootPtr=Insert(rootPtr,8);
rootPtr=Insert(rootPtr,12);

inorder(rootPtr);
cout<<endl;
rootPtr=Delete(rootPtr,12);
cout<<"After deleting 12 from the tree:";
inorder(rootPtr);
rootPtr=Delete(rootPtr,20);
cout<<endl<<"After deleting 20 from the tree:";
inorder(rootPtr);
return 0;
}

OUTPUT:
8 10 12 15 20 25
After deleting 12 from the tree:8 10 15 20 25
After deleting 20 from the tree:8 10 15 25
3. From the figure below, identify

i. root ➔A
ii. Height of tree ➔3
iii. Degree ➔3
iv. Size➔9
v. leaf node(s)➔D,E,F,G,I

4. Draw a tree from the following representation: and identify


i. Child of H ➔ D,K
ii. Height of Tree➔3
iii. Leaf node(s)➔E,G,C,A,I,L
iv. Parent of A➔B

D➔F B➔C K➔J H➔D F➔E J➔I


D➔B B➔A K➔L H➔K F➔G
5. write down the applications of Tree data structure
• Computer File System (Data contained in a hierarchical manner like drives,
folders subfolders, files etc.)
• As a workflow for composing digital images for visual effects
• Decision trees (Machine learning algorithms)
• Store data in routing tables in the routers
• Organization chart of a large organization
• IN server like DNS (Domain Name Server)
• Computer Graphics
• In a chess game to store defense moves of a player
Lab 10 Tree Traversal Algorithms
i. Inorder ii. Preorder iii. Postorder
1. Traverse the following binary trees using the pre, in, and post order traversal
methods.

Preorder: +, *,3,5, -,2, /,8,4


Inorder: (3*5) + (2-(8/4))
Postorder: 3,5, *,2,8,4, /, -, +

Preorder: 2 7 2 6 5 11 5 9 4
Inorder: 2 7 5 6 11 2 5 4 9
Postorder: 2 5 11 6 7 4 9 5 2
2. Implement all three tree traversal algorithms , also determine the worst time
complexity.
WORST TIME COMPLEXITY
Preorder: O(N)
Inorder: O(N)
Postorder: O(N)
Where N is the size of Binary tree(Since we traverse all the nodes, we have to go
to every single node hence time is dependent on number of nodes.)
INPUT:
#include<bits/stdc++.h>
using namespace std;
struct BSTNode
{
int data;
BSTNode* left;
BSTNode* right;
BSTNode(int val)
{
data=val;
left=NULL;
right=NULL;
}
};
BSTNode* Insert(BSTNode* root,int val)
{
if(root==NULL)
{
return new BSTNode(val);
}
else if(val<root->data)
{
root->left=Insert(root->left,val);
}
else
{
root->right=Insert(root->right,val);
}
return root;
}
void preorder(BSTNode* root)
{
if(root==NULL)
{
return;
}
cout<<root->data<<" ";
preorder(root->left);
preorder(root->right);
}
void inorder(BSTNode *root)
{
if(root==NULL)
{
return;
}
inorder(root->left);
cout<<root->data<<" ";
inorder(root->right);
}
void postorder(BSTNode* root)
{
if(root==NULL)
{
return;
}
postorder(root->left);
postorder(root->right);
cout<<root->data<<" ";
}
int main()
{
BSTNode* rootPtr=NULL;
rootPtr=Insert(rootPtr,15);
rootPtr=Insert(rootPtr,10);
rootPtr=Insert(rootPtr,20);
rootPtr=Insert(rootPtr,25);
rootPtr=Insert(rootPtr,8);
rootPtr=Insert(rootPtr,12);
cout<<"PreOrder:";
preorder(rootPtr);
cout<<endl<<"InOrder:";
inorder(rootPtr);
cout<<endl<<"PostOrder:";
postorder(rootPtr);
cout<<endl;
return 0;
}

OUTPUT:
PreOrder:15 10 8 12 20 25
InOrder:8 10 12 15 20 25
PostOrder:8 12 10 25 20 15
3. Given a binary tree, write an efficient algorithm to convert the binary tree into
its mirror.
For example, the following binary trees are mirrors of each other: (also give
implementation)

Hint: traverse the tree in a preorder fashion, and for every node, swap its left and
right child pointer after recursively converting its left and right subtree to mirror
first.
ALGORITHM
Mirror(node* root)
1.Call Mirror(root->left)
2. Call Mirror(root->right)
3.Swap left and right subtrees of the root
INPUT:
#include<bits/stdc++.h>
using namespace std;
struct BSTNode
{
int data;
BSTNode* left;
BSTNode* right;
BSTNode(int val)
{
data=val;
left=NULL;
right=NULL;
}
};
BSTNode* Insert(BSTNode* root,int val)
{
if(root==NULL)
{
return new BSTNode(val);
}
else if(val<root->data)
{
root->left=Insert(root->left,val);
}
else
{
root->right=Insert(root->right,val);
}
return root;
}
void preorder(BSTNode* root)
{
if(root==NULL)
{
return;
}
cout<<root->data<<" ";
preorder(root->left);
preorder(root->right);
}
void inorder(BSTNode *root)
{
if(root==NULL)
{
return;
}
inorder(root->left);
cout<<root->data<<" ";
inorder(root->right);
}
void mirror(BSTNode*& root)
{
if(root)
{
mirror(root->left);
mirror(root->right);
BSTNode* temp=root->left;
root->left=root->right;
root->right=temp;
}
return;

int main()
{
BSTNode* rootPtr=NULL;
rootPtr=Insert(rootPtr,15);
rootPtr=Insert(rootPtr,10);
rootPtr=Insert(rootPtr,20);
rootPtr=Insert(rootPtr,25);
rootPtr=Insert(rootPtr,8);
rootPtr=Insert(rootPtr,12);
cout<<"PreOrder of Tree:";
preorder(rootPtr);
cout<<endl<<"InOrder of Tree:";
inorder(rootPtr);
cout<<endl<<endl;
mirror(rootPtr);
cout<<"PreOrder of Mirror Tree:";
preorder(rootPtr);
cout<<endl;
cout<<"InOrder of Mirror Tree:";
inorder(rootPtr);
return 0;
}
OUTPUT:
PreOrder of Tree:15 10 8 12 20 25
InOrder of Tree:8 10 12 15 20 25

PreOrder of Mirror Tree:15 20 25 10 12 8


InOrder of Mirror Tree:25 20 15 12 10 8
Lab 11 Graph Data Structure
1. Gives the algorithms for adjacency list and adjacency matrix methods ,also
determine their time complexity.
ADJACENCY LIST ALGORITHM
1.Create a class called Graph which will store vertex of the graph and adres of it’s
adjacent vertex.
2.Create a function to add Edges to the graph
AddEdges(adj_list,u,v)
a) Append v into list at index u of adj_list
b) Append u into the list at index v of adj_list
TIME COMPLEXITY
O (1) [constant ] for adding an edge as it involves simple assignment statements
ADJACENCY MATRIX ALGORITHM:
AddEdge(A,B)
1.Declare a two dimensional matrix of size N x N
2. Initialize all values of matrix to 0
3.Assign matrix[A][B]=1 and [B][A]=1
4.Update the matrix
TIME COMPLEXITY
O (1) [constant ] for adding an edge as it involves simple assignment statements
2. Assume an undirected graph having 4 vertices 0,1,2,3. the vertices are connected
in following manner 0➔1, 0➔2, 1➔0, 1➔2, 2➔3, 3➔2. Implement graph DS
by using Adjacency list and Adjacency Matrix method.
ADJACENCY LIST
INPUT:
#include<bits/stdc++.h>
using namespace std;
class Graph
{
int Vertex;
//array of list(linked list)
list<int>*l;
//we can do list<int>*l[v]; but we donot know v
public:
Graph(int v)
{
this->Vertex=v;
//l is a pointer to an array in which
//each element of the array is a list
l=new list<int>[v];//dynamic location
}
void addEdge(int x,int y)
{
l[x].push_back(y);
l[y].push_back(x);
}
void Display()
{
//iterate over all vertices
for(int i=0;i<Vertex;i++)
{
cout<<"Vertex "<<i<<"->";
for (int neighbour:l[i])
{
cout<<" "<<neighbour<<" ";
}
cout<<endl;
}
}
};
int main()
{
Graph g(4);
g.addEdge(0,1);
g.addEdge(0,2);
g.addEdge(2,3);
g.addEdge(1,2);
g.Display();
return 0;
}

OUTPUT:
Vertex 0-> 1 2
Vertex 1-> 0 2
Vertex 2-> 0 3 1
Vertex 3-> 2

ADJACENCY MATRIX
INPUT:
#include<bits/stdc++.h>
using namespace std;
class graph
{
int Vertex;
//pointer to 1D array
int **AdjMatrix;//pointer to pointer variable
public:
graph(int v)
{
this->Vertex=v;
AdjMatrix=new int*[v];
for (int row=0;row<v;row++)
{
AdjMatrix[row]=new int[v];
for(int col=0;col<v;col++)
{
AdjMatrix[row][col]=0;
}
}
}
void AddEdge(int x,int y)
{
AdjMatrix[x][y]=1;
AdjMatrix[y][x]=1;
}
void Display()
{
for(int i=0;i<Vertex;i++)
{
for (int j=0;j<Vertex;j++)
{
cout<<" "<<AdjMatrix[i][j]<<" ";
}
cout<<endl;
}
}
};
int main()
{
graph g(4);
//g.Display();
g.AddEdge(0,1);
g.AddEdge(0,2);
g.AddEdge(1,2);
g.AddEdge(2,3);

g.Display();

return 0;
}
OUTPUT:
0 1 1 0
1 0 1 0
1 1 0 1
0 0 1 0

3. Differentiate between graph and Tree data structure.


Graph Data Structures Tree Data Structures
Have vertices and edges Have nodes and edges
Graphs can have more than one path Trees can have only one path between two
between vertices(directed/undirected) vertices(directed)
It is traversed by using BFS and DFS It is traversed through Pre-order, In-order
techniques and Postorder techniques.
Network Hierarchy
Complex Simpler
Its edges are not defined by a formula Its edges are always equal to n-1 where n is
the number of nodes.
Can form a circular loop Cannot form a circular loop
Applications: Applications:
Social media e.g Facebook to send friend Storing Dictionaries
requests Computer File system
Used in maps Inserting, Deleting and Searching for
Used in networking to find shortest path elements
Lab 12 Graph Traversal Algorithms
i. DFS ii. BFS

1. give Implementation of depth & breadth first search algorithms on graph (lab 11
Q2)
BREADTH FIRST SEARCH
INPUT:
#include<bits/stdc++.h>
using namespace std;

template<typename T>
//so you can work with a graph of integers as well as strings
class Graph
{
//map<datatype,list<dataType>> variableName
//key value pair
map<T,list<T>>l;

public:
void addEdge(int x,int y)//bidirectional
{
l[x].push_back(y);
l[y].push_back(x);
}
void BFS(T sourceNode)
{
map<T,int> visited;
queue<T> q;

q.push(sourceNode);
visited[sourceNode]=true;
while(!q.empty())
{
T node=q.front();
q.pop();
cout<<node<<" ";
for(int adjacent:l[node])//l[node] gives me value of the
node
//values contain adjacency list/neighbours of that
{
if(!visited[adjacent])
{
q.push(adjacent);
//mark the adjacent as visited
visited[adjacent]=true;
}
}
}

}
};
int main()
{
Graph<int> g;
g.addEdge(0,1);
g.addEdge(1,2);
g.addEdge(2,3);
g.addEdge(3,4);
g.addEdge(4,5);

g.BFS(0);
return 0;
}

OUTPUT:
012345
DEPTH FIRST SEARCH
INPUT:
#include<bits/stdc++.h>
using namespace std;
//so you can work with a graph of integers as well as strings
template<typename T>
class Graph
{
//map<datatype,list<dataType>> variableName
//key value pair
map<T,list<T>>l;

public:
void addEdge(int x,int y)//bidirectional
{
l[x].push_back(y);
l[y].push_back(x);
}
void DFS_HELPER(T SourceNode,map<T,bool>&visited)
{
//recursive function that will traverse the graph
cout<<SourceNode<<" ";
visited[SourceNode]=true;
//go to all adjacent of node not visited one by one
for(T adj:l[SourceNode])
{
if(!visited[adj])
{
DFS_HELPER(adj,visited);
}
}

}
void DFS(T SourceNode)
{
map<T,bool>visited;
//mark all the nodes as not visited in the beginning
//auto keyword is a simple way to declare a variable that has
a complicated type
for(auto p:l)
{
T node=p.first;
visited[node]= false;
}
//call helper function
DFS_HELPER(SourceNode,visited);
}
};
int main()
{
Graph<int> g;
g.addEdge(0,1);
g.addEdge(1,2);
g.addEdge(2,3);
g.addEdge(3,4);
g.addEdge(4,5);
g.addEdge(3,0);

g.DFS(0);
return 0;
}

OUTPUT:
012345
2. Differentiate DFS and BFS : Also state which traversing method is best suited in
what circumstances?
Depth First Search Breadth First Search
Data Uses Stack to find the shortest Uses Queue to find DFS uses Stack to
Structure path. find the structure the shortest path.
Source Better when target is far from Better when target is close to the
source source
Speed Faster Slower
Time O(V+E) where V is vertices and O(V+E) where V is vertices and E
Complexity E vertices and E is edges. vertices and E is edges.
Memory Requires less memory Requires more memory
Application Suitable for gaming and puzzle Not suitable for decision making trees
problems used in games or puzzles as it
considers all neighbours in general

3.Write algorithm to Determine whether an undirected graph is a tree (Acyclic


Connected Graph); Also give implementation. Analyzes your algorithm and
identify the worst time complexity and upper bound.
ALGORITHM:
1.Iterate over all nodes of graph and keep a visited array to track the visited nodes
Initialize the whole visited array as false/0/not visited
2.Run a Depth First Traversal on subgraph adjacent to the current node. In each
recursion:
a) Set visited[node] as true (node has been visited)
b) Iterate over all neighboring nodes of the node in the adjacency list
IF not visited then
run DFS and return true if DFS returns true
ELSE IF neighboring node is not the parent node of current node
Returns true
c) Return false
TIME COMPLEXITY
O(V+E) since it is a simple DFS traversal of graph represented by an adjacency list
INPUT:
#include<bits/stdc++.h>
using namespace std;

class Graph
{
int Vertex;
list<int>*l;

public:
Graph(int v)
{
this->Vertex=v;
//l is a pointer to an array in which
//each element of the array is a list
l=new list<int>[v];//dynamic location
}

void addEdge(int x,int y,bool directed=true)


{
l[x].push_back(y);
if(!directed)
{
l[y].push_back(x);
}
}
bool cycle_helper(int node,bool* visited ,int parent )
{
visited[node]=true;
for(auto adj:l[node])
{
//two cases
if(!visited[adj])
{
//go and recursively visit the adjacent
bool cycle_identified=cycle_helper(adj,visited,node);
if(cycle_identified)
{
return true;
}
}
else if(adj!=parent)//adjacent visited is not the parent
{
return true;
}
}
return false;
}
bool DetectCycle()
{
//checks for cycle
bool *visited=new bool[Vertex];
for (int i=0;i<Vertex;i++)
{
visited[i]=false;
}
return cycle_helper(0,visited,-1);
}
};
//graph contains a cycle if there is more than one way to visit any
node
//for any node if you are iterating over its adjacents the ith node
shouldnot
//be the parent of that node as well

int main()
{
Graph g(4);
g.addEdge(0,1);
g.addEdge(1,2);
g.addEdge(2,3);
g.addEdge(3,4);
g.addEdge(4,0);
cout<<"Graph 1"<<endl;
if(g.DetectCycle())
{
cout<<"Yes undirected graph contains cycle"<<endl;
}
else
{
cout<<"No ,the graph doesnot contain a cycle"<<endl;
}

Graph g1(4);
g.addEdge(0,1);
g.addEdge(1,2);
g.addEdge(2,3);
g.addEdge(3,4);
cout<<endl<<"Graph 2"<<endl;
if(g1.DetectCycle())
{
cout<<"Yes undirected graph contains cycle"<<endl;
}
else
{
cout<<"No ,the graph doesnot contain a cycle"<<endl;
}
return 0;
}

OUTPUT:
Graph 1
Yes undirected graph contains cycle

Graph 2
No ,the graph doesnot contain a cycle
Lab 13 Rat in a Maze
1.What approach do you used to solve problem and why?
The maze is represented by an N x N matrix (a graph).The concept of backtracking
is employed which solves computational problems recursively by trying to build a
solution incrementally. Hence we also used recursion because we have to
continuously check on which position to move next and we can only move in the x
direction and y direction.
We use backtracking to explore all the possible paths from a given vertex. Using
this, we either find a position to move to next or try another path /edge again. This
continues until we reach our destination. Hence, we use this approach because it
finds out all possible paths easily and uses recursion for locating them.

2. Give the algorithm of above problem, also analyze the time & space complexity
of your algorithm.
1. Create a solution matrix filled with 0’s
2.Recursive Function SolveMazeUntil(initial matrix,output matrix,int I ,int j)
3.Check if position of the rat is valid or not.
IF position is not valid then
Return
4.Mark the position [i][j] of output matrix as 1
5.Check if current position is the destination or not
IF current position is destination then
Print output matrix and Return
6.Recursive call for position (i+1, j) and (i,j+1)
7.Unmark position by simply output matrix[i][j]=0

Space Complexity is O(N2) because of the two dimensional array of size N*N
2
Time Complexity is O(2𝑁 ) because we need to consider two different paths at
every position .
3. Give implementation of Rat in a Maze problem.
INPUT:
#include<iostream>
using namespace std;

const int N=4;

bool isValid(int maze[N][N],int i,int j)


{
//if position of rat is outside the maze,return false
if(i>=0 && i<N && j>=0 && j<N && maze[i][j]==1)
{
return true;
}
return false;
}

bool solveMazeUntil(int maze[N][N],int i,int j,int sol[N][N])


{
//if position of rat is in the destination
if(i==N-1 && j==N-1 && maze[i][j]==1)
{
sol[i][j]=1;
return true;
}
//check if maze[i][j] is valid
if(isValid(maze,i,j)==true)
{
//if current position is already in solution path
if(sol[i][j]==1)
{
return false;
}
sol[i][j]=1;
//now move forward in x direction
if(solveMazeUntil(maze,i+1,j,sol)==true)
{
return true;
}
//else move in y direction
if(solveMazeUntil(maze,i,j+1,sol)==true)
{
return true;
}
//if none of movement works then donot mark i and j as
solution path
sol[i][j]=0;
return false;
}
return false;
}
void printSolution(int sol[N][N])
{
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
cout<<" "<<sol[i][j]<<" ";
cout<<endl;
}
}
bool solveMaze(int maze[N][N])
{
int sol[N][N]={ { 0, 0, 0, 0 },
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 } };
if(solveMazeUntil(maze,0,0,sol)==false)
{
cout<<"Solution doesn't exist";
return false;
}
printSolution(sol);
return true;
}

int main()
{
int maze[N][N] = { { 1, 0, 0, 0 },
{ 1, 1, 0, 1 },
{ 0, 1, 0, 0 },
{ 1, 1, 1, 1 } };
solveMaze(maze);
return 0;
}

OUTPUT:
1 0 0 0
1 1 0 0
0 1 0 0
0 1 1 1
Lab 14 N- Queen Problem
1.What approach do you used to solve problem and why?
The chessboard is represented by an NxN matrix. We apply the concept of
backtracking which is a general algorithmic technique in which all possible
combinations are considered in order to solve a problem.
We use backtracking because if the position of one of the queens is incorrect, we
can backtrack to correct it and try out other positions.
Backtracking also involves use of recursive functions hence recursion concept is
also used here.
Backtracking is a Depth First Search Technique as well meaning it involves
traversal of Graph(in this case the matrix)

2. Give the algorithm of above problem, also analyze the time & space complexity
of your algorithm.
ALGORITHM
1.Create a N by N matrix to collect all solution states
2.Start in topmost row
3.IF all queens are placed
Return true
4.Try out all the columns in the current row. Perform the following for every tried
column
a) Safe function checks current column, right diagnol and left diagnol. If queen
can be placed safely in the column, mark this position as part of solution and
recursively check if placing queen here leads to a solution
b) IF placing queen in this position leads to a solution,
Return true
c)IF placing queen does not lead to a solution
Unmark the position
Go back to part a to try other columns
5.IF all columns have been tried and nothing works
Return false to trigger backtracking
TIME COMPLEXITY
O(N!)
When you assign a location of the queen in the first row, you have n options, after
that, you only have n-1 options as you can't place the queen in the same row as the
first queen, then n-2 and so on.
E.g if N=4
For the first row, since none is filled in the matrix as a whole, we have 4 options.
For the second row, we have 3 options as one row has already been taken off.
Similarly, for the third row, we have 2 options and for the final row, we are left
with just 1 option.
Total options = 4*3*2*1 = 24 (4!)
Since N=4
T(N)=N!
SPACE COMPLEXITY
Since we are using NxN matrix, Space Complexity will be O(N2)
3. Give implementation of Rat in a Maze problem.
INPUT:
#include<bits/stdc++.h>
using namespace std;
//queen can attack from up ,doen ,left ,right and diagonal
//every queen placed in a different row
//every queen placed in a different column
//no queen to lie in another's diagnol

bool isSafe(int** arr,int x,int y,int n)


{
//you donot chec for row as you will iterative reach the row
//check whether each column has another queen
for(int row=0;row<x;row++)
{
if(arr[row][y]==1)
{
return false;
}
}
//check for the two diagnols
//row-- and column--(for left diagnol) and row-- and column++(for
right diagnol)
int row=x;
int column=y;
while (row>=0 && column>=0)
{
if(arr[row][column]==1)//if position already occupied
{
return false;
}
row--;
column--;
}
row=x;
column=y;
while (row>=0 && column<n)//to not get out of board
{
if(arr[row][column]==1)//if position already occupied
{
return false;
}
row--;
column++;
}
return true;
}

bool NQueen(int** arr,int ROW,int n)


{
if(ROW>=n)//n queens are placed
{
return true;
}
for (int COLUMN=0;COLUMN<n;COLUMN++)
{
if(isSafe(arr,ROW,COLUMN,n))
{
arr[ROW][COLUMN]=1;
if(NQueen(arr,ROW+1,n))
{
return true;
}
arr[ROW][COLUMN]=0;//backtracking
}
}
return false;
}
int main()
{
int NUM;
cout<<"Enter a number (n) for which you will have an nxn matrix
and place n queens:";
cin>>NUM;
int** arr=new int*[NUM];
//initilizing 2D array
for(int i=0;i<NUM;i++)
{
arr[i]=new int[NUM];
for(int j=0;j<NUM;j++)
{
arr[i][j]=0;
}
}
if(NQueen(arr,0,NUM))
{
//print array
for (int i=0;i<NUM;i++)
{
for(int j=0;j<NUM;j++)
{
cout<<arr[i][j]<<" ";
}
cout<<endl;
}
}
return 0;
}

OUTPUT:
Sample Test 1
Enter a number (n) for which you will have an nxn matrix and place n queens:4
0100
0001
1000
0010
Sample Test 2
Enter a number (n) for which you will have an nxn matrix and place n queens:7
1000000
0010000
0000100
0000001
0100000
0001000
0000010

You might also like