You are on page 1of 18

Kinnaird College for Women, Lahore

Design and Analysis of Algorithms


Pre-Mid Assignment 1
Instructor: Ms. Rida Hijab
Submitted By: Sania Aimen – F21BSCS051
Submission Date: 20th Feb, 2023
Q1. Against each category listed below, name and describe (in your own words) a class
of problems from CS, for instance, we know that searching through a random list is a
linear time operation.

1. lg n
In the class sorting problems, many sorting algorithms have the lg n time complexity.
 Like a binary search algorithm that divides the sorted input data into separate
halves in each iteration. Since the search space is halved at each iteration, it only
takes log base 2 to the n iterations to complete the search, where n is the size of
the array.
2. Sqrt n
Sqrt n time complexity means that if the input size is n then there are approximately sqrt n
basic operations, in the case of sorting algorithms comparisons.
 For instance, finding the kth smallest element in an unsorted array. The basic idea
is to divide the array into blocks of size sqrt n and then find the median.
 Another problem is of the range queries in a one-dimensional array or database
queries etc.
3. N
n is used for the time complexity in which we have to traverse the whole array or list of
input values. It depends on the size of the input.
 In searching algorithms to find the key element a linear search is conducted that
takes O(n) time complexity.
 Traversing through a linked list also takes O(n) time
 Finding the min and max elements in an array requires iterating through each
element
 Also in sorting algorithms it takes n comparisons to sort the array, hence taking
O(n) time to be sorted.
4. N lg N
O(n lg n) time complexity means that the lg n operations will occur n times. It is
associated with divide-and-conquer algorithms. They work by dividing the problem into
smaller sub-problems, solving the sub-problems recursively, and then combining the
solutions and the sub-problems to find the answer.
 Merge sort: recursively divides the array into halves and at the end combines the
sorted halves into one sorted array.
 Quick sort: Selects a pivot point and divide the array on the basis of less and
greater than the pivot.
 Heapsort: Finds the key element and puts it at the end of the array.
The above mentioned divide and conquer algorithms all have O(n lg n) time complexity
5. N^2
The class of computer science problems associated that has the time complexity of n^2
are usually related to the algorithms that use nested loops. These algorithms work on pair
of elements, which results in the number of operations increasing quadratically with the
input size.
 Bubble sort: Compares the pair of elements and moves the largest element at the
end of the array
 Inserting sort: Sorts the elements as they are inserted into their proper place in the
array
 Selection sort: Sorts repeatedly by selecting the smallest element and swapping
with the first sorted element the array
 Shorted paths: shortest paths algorithms find the path using the nested loop
approach.
All of the above mentioned problems have O(n^2) time complexity.
6. N^3
When the algorithm runs over 3 nested loops then the algorithm is said to have cubic time
complexity.
Here are some CS related problems that have cubic time complexity:
 Matrix multiplication: Computing the product of two n x n matrices and the
resulting matrix is the sum of n products.
 Determinant of a matrix: Calculating the determinant of the matrix is done by
using b cofactor expansion and takes n^3 time.
 Calculating the inverse of a matrix: reducing the matrix by Gaussian elimination
and then applying back substituting
All these problems have n^3 time complexity.
7. 2^n
2^n time complexity is associated with the exponential growth of the algorithm
depending on the input size n and is observed in recursive algorithms.
Following are some problems that exhibit the time complexity of 2^n:
 Recursive algorithms that perform a task recursively until they reach the base case.
 Generating all subsets of a set requires evaluating 2^n possible subsets.
8. N! (Factorial time)
The n! time complexity is associated with problems involving calculating permutations
and combinations of a given set of items.
Some examples of algorithms have O(n!) time complexity is:
 Traveling salesman problem: It finds all the permutations of the cities to find the
shortest route.
 Generating subsets of a set: All possible ways to find k items from a set of n
elements
Q2.
 Selection sort
Code:
#include <iostream>
#include <chrono>
using namespace std;

// Selection sort in C++

#include <iostream>
using namespace std;

// function to swap the the position of two elements


void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}

void selection_sort(int array[], int size) {


for (int step = 0; step < size - 1; step++) {
int min_idx = step;
for (int i = step + 1; i < size; i++) {

// To sort in descending order, change > to < in this line.


// Select the minimum element in each loop.
if (array[i] < array[min_idx])
min_idx = i;
}
// put min at the correct position
swap(&array[min_idx], &array[step]);
}
}

int main(){
int arr1[50] = {5, 15, 37, 42, 47, 146, 165, 168, 171, 177, 192, 216, 218, 221, 237, 282,
296, 343,
425, 429, 439, 484, 485, 491, 513, 514, 519, 522, 535, 546, 574, 594, 600, 690, 701, 730,
743, 755,
770, 794, 795, 810, 815, 828, 849, 866, 876, 884, 918, 946};

int n = sizeof(arr1) / sizeof(arr1[0]);

int trials = 10;


double total_time = 0;

for(int i=0; i<trials; i++){


auto start = chrono::high_resolution_clock::now();
selection_sort(arr1, n);
auto end = chrono::high_resolution_clock::now();
double time_taken = chrono::duration_cast<chrono::nanoseconds>(end - start).count();
cout << "Time taken for trial " << i+1 << ": " << time_taken / 1e9 << " seconds" <<
endl;
total_time += time_taken;
}
cout<<endl;
double avg_time = total_time / trials;
cout << "Average time taken for best case " << trials << " trials: " << avg_time / 1e9 << "
seconds" << endl;
cout<<endl;
int arr2[150] = {91, 81, 127, 92, 61, 123, 50, 118, 39, 146, 93, 104, 31, 145, 125, 71, 35, 6,
67, 43, 23,
58, 80, 135, 40, 34, 105, 70, 137, 126, 77, 14, 100, 113, 107, 56, 111, 2, 133, 149, 30, 49,
132, 147,
76, 117, 116, 16, 144, 143, 26, 112, 1, 51, 139, 87, 109, 54, 130, 7, 37, 119, 150, 69, 5, 73,
129, 124,
47, 78, 138, 57, 98, 41, 86, 84, 89, 115, 42, 18, 148, 128, 83, 134, 96, 90, 4, 102, 94, 44,
121, 46, 101,
88, 3, 110, 79, 141, 10, 28, 20, 108, 29, 64, 32, 85, 59, 36, 75, 62, 25, 65, 68, 17, 52, 66,
106, 8, 72,
99, 55, 27, 53, 140, 11, 13, 48, 60, 15, 12, 33, 63, 122, 114, 22, 24, 82, 103, 142, 97, 21,
38, 45, 136,
120, 95, 9, 131, 19, 74};

int m = sizeof(arr2) / sizeof(arr2[0]);

trials = 10;
double total_time2 = 0;

for(int i=0; i<trials; i++){


auto start = chrono::high_resolution_clock::now();
selection_sort(arr2, n);
auto end = chrono::high_resolution_clock::now();
double time_taken2 = chrono::duration_cast<chrono::nanoseconds>(end - start).count();
cout << "Time taken for trial " << i+1 << ": " << time_taken2 / 1e9 << " seconds" <<
endl;
total_time2 += time_taken2;
}
cout<<endl;
double avg_time2 = total_time2 / trials;
cout << "Average time taken for average case " << trials << " trials: " << avg_time2 / 1e9
<< " seconds" << endl;
cout<<endl;

int arr3[250] =
{300,299,296,295,294,293,292,291,290,289,288,286,285,284,283,282,281,280,279,278,277,
276,275,

274,273,272,271,270,269,267,266,265,263,262,261,260,259,258,257,256,255,254,253,251,2
50,248,247,246,245,244,

242,240,239,238,237,236,235,234,233,232,231,230,229,228,227,226,225,223,222,221,220,2
19,218,217,216,215,214,

213,210,209,208,207,206,204,203,202,200,199,198,197,196,195,194,193,192,190,189,188,1
87,186,185,184,183,182,

181,180,179,178,177,176,175,173,172,171,170,168,166,165,164,163,162,161,160,159,158,1
57,156,155,154,152,151,

150,149,147,145,144,143,141,140,138,137,136,135,133,132,131,130,129,128,125,124,123,1
22,121,120,118,117,115,

114,113,111,110,109,108,106,105,104,103,101,100,99,98,97,96,95,91,90,88,87,86,85,84,82,
81,80,79,78,77,76,74,

72,71,70,69,68,67,66,64,63,61,59,58,57,56,54,53,52,51,50,49,48,47,46,45,44,43,42,41,39,38,
37,35,34,33,32,31,
30,28,27,26,24,23,22,21,20,18,16,15,14,13,11,10,9,8,7,6,4,3,2,1};

int p = sizeof(arr3) / sizeof(arr3[0]);

trials = 10;
double total_time3 = 0;

for(int i=0; i<trials; i++){


auto start = chrono::high_resolution_clock::now();
selection_sort(arr3, n);
auto end = chrono::high_resolution_clock::now();
double time_taken3 = chrono::duration_cast<chrono::nanoseconds>(end - start).count();
cout << "Time taken for trial " << i+1 << ": " << time_taken3 / 1e9 << " seconds" <<
endl;
total_time3 += time_taken3;
}
cout<<endl;
double avg_time3 = total_time3 / trials;
cout << "Average time taken for worst case " << trials << " trials: " << avg_time3 / 1e9 <<
" seconds" << endl;
cout<<endl;

<chrono> is a header file in the C++ standard library that provides functions for measuring
time complexity and time points.

 Insertion Sort
Code:
#include <iostream>
#include <chrono>
using namespace std;

void insertion_sort(int array[], int size) {


for (int step = 1; step < size; step++) {
int key = array[step];
int j = step - 1;
while (key < array[j] && j >= 0) {
array[j + 1] = array[j];
--j;
}
array[j + 1] = key;
}
}

int main(){
int arr1[50] = {5, 8, 9, 13, 14, 18, 20, 22, 28, 33, 38, 45, 52, 53, 55, 58, 65, 67, 70, 71, 73,
76, 84, 87,
88, 93, 95, 96, 100, 101, 109, 111, 115, 120, 121, 127, 134, 136, 138, 139, 140, 143, 150,
151, 153, 155, 175,
182, 193, 196};

int n = sizeof(arr1) / sizeof(arr1[0]);

int trials = 10;


double total_time = 0;

for(int i=0; i<trials; i++){


auto start = chrono::high_resolution_clock::now();
insertion_sort(arr1, n);
auto end = chrono::high_resolution_clock::now();
double time_taken = chrono::duration_cast<chrono::nanoseconds>(end - start).count();
cout << "Time taken for trial " << i+1 << ": " << time_taken / 1e9 << " seconds" <<
endl;
total_time += time_taken;
}
cout<<endl;
double avg_time = total_time / trials;
cout << "Average time taken for best case " << trials << " trials: " << avg_time / 1e9 << "
seconds" << endl;
cout<<endl;

int arr2[150] = {565, 956, 84, 786, 719, 546, 419, 310, 656, 733, 265, 710, 295, 108, 949,
332, 118, 342,
423, 307, 799, 36, 247, 392, 35, 248, 688, 70, 99, 679, 158, 840, 151, 261, 74, 89, 478,
473, 901, 129,
649, 122, 970, 125, 259, 42, 858, 689, 600, 428, 405, 629, 847, 740, 416, 987, 921, 348,
928, 782, 486,
828, 487, 770, 438, 226, 479, 822, 854, 394, 678, 481, 622, 807, 974, 195, 243, 643, 385,
570, 850, 601, 716,
119, 463, 667, 610, 950, 418, 399, 209, 288, 661, 554, 341, 366, 176, 924, 154, 222, 808,
311, 105, 789, 56,
758, 668, 980, 464, 467, 485, 833, 897, 836, 682, 997, 552, 316, 318, 278, 819, 269, 746,
747, 726, 961, 324,
101, 407, 775, 834, 305, 748, 572, 338, 973, 511, 771, 879, 756, 513, 17, 337, 495, 715,
466, 116, 881, 15,
170};

int m = sizeof(arr2) / sizeof(arr2[0]);

trials = 10;
double total_time2 = 0;

for(int i=0; i<trials; i++){


auto start = chrono::high_resolution_clock::now();
insertion_sort(arr2, n);
auto end = chrono::high_resolution_clock::now();
double time_taken2 = chrono::duration_cast<chrono::nanoseconds>(end - start).count();
cout << "Time taken for trial " << i+1 << ": " << time_taken2 / 1e9 << " seconds" <<
endl;
total_time2 += time_taken2;
}
cout<<endl;
double avg_time2 = total_time2 / trials;
cout << "Average time taken for average case " << trials << " trials: " << avg_time2 / 1e9
<< " seconds" << endl;
cout<<endl;

int arr3[250] =
{1997,1993,1984,1979,1970,1969,1967,1960,1946,1930,1919,1910,1908,1898,1889,1885,18
61,1859,

1855,1853,1852,1849,1843,1832,1827,1822,1820,1813,1807,1775,1774,1773,1763,1762,175
6,1754,1746,1741,1738,

1723,1721,1705,1693,1691,1667,1657,1633,1612,1604,1582,1576,1572,1556,1554,1549,153
6,1532,1531,1529,1525,

1514,1508,1504,1503,1483,1481,1472,1467,1461,1459,1455,1437,1434,1430,1427,1415,139
9,1386,1373,1369,1357,

1339,1325,1320,1316,1314,1313,1304,1290,1288,1277,1266,1260,1253,1236,1224,1223,121
6,1213,1202,1192,1186,

1183,1169,1162,1141,1140,1135,1129,1127,1122,1120,1116,1113,1094,1087,1075,1069,106
0,1042,1029,999,990,978,

965,964,955,941,926,925,921,919,907,895,894,886,868,858,849,832,826,813,808,803,795,7
75,769,740,738,736,731,

729,725,723,719,715,712,705,700,686,685,676,672,668,666,662,652,646,645,636,633,631,6
25,615,607,600,592,590,

584,583,578,554,537,533,529,525,518,506,494,484,481,470,454,441,436,430,425,422,401,3
95,388,369,362,347,343,

340,317,312,306,301,300,299,274,265,259,228,224,220,209,205,198,190,188,182,181,167,1
50,142,133,125,118,116,
111,110,99,98,90,74,63,53,51,44,41,37,35,33,32,27,22,13};

int p = sizeof(arr3) / sizeof(arr3[0]);


trials = 10;
double total_time3 = 0;

for(int i=0; i<trials; i++){


auto start = chrono::high_resolution_clock::now();
insertion_sort(arr3, n);
auto end = chrono::high_resolution_clock::now();
double time_taken3 = chrono::duration_cast<chrono::nanoseconds>(end - start).count();
cout << "Time taken for trial " << i+1 << ": " << time_taken3 / 1e9 << " seconds" <<
endl;
total_time3 += time_taken3;
}
cout<<endl;
double avg_time3 = total_time3 / trials;
cout << "Average time taken for worst case " << trials << " trials: " << avg_time3 / 1e9 <<
" seconds" << endl;
cout<<endl;

 Bubble Sort
Code:
#include <iostream>
#include <chrono>
using namespace std;

void bubble_sort(int array[], int size) {

for (int step = 0; step < size; ++step) {


for (int i = 0; i < size - step; ++i) {

if (array[i] > array[i + 1]) {

int temp = array[i];


array[i] = array[i + 1];
array[i + 1] = temp;
}
}
}
}

int main(){
int arr1[50] = {5, 8, 9, 13, 14, 18, 20, 22, 28, 33, 38, 45, 52, 53, 55, 58, 65, 67, 70, 71, 73,
76, 84, 87,
88, 93, 95, 96, 100, 101, 109, 111, 115, 120, 121, 127, 134, 136, 138, 139, 140, 143, 150,
151, 153, 155, 175,
182, 193, 196};

int n = sizeof(arr1) / sizeof(arr1[0]);

int trials = 10;


double total_time = 0;

for(int i=0; i<trials; i++){


auto start = chrono::high_resolution_clock::now();
bubble_sort(arr1, n);
auto end = chrono::high_resolution_clock::now();
double time_taken = chrono::duration_cast<chrono::nanoseconds>(end - start).count();
cout << "Time taken for trial " << i+1 << ": " << time_taken / 1e9 << " seconds" <<
endl;
total_time += time_taken;
}
cout<<endl;
double avg_time = total_time / trials;
cout << "Average time taken for best case " << trials << " trials: " << avg_time / 1e9 << "
seconds" << endl;
cout<<endl;

int arr2[150] = {565, 956, 84, 786, 719, 546, 419, 310, 656, 733, 265, 710, 295, 108, 949,
332, 118, 342,
423, 307, 799, 36, 247, 392, 35, 248, 688, 70, 99, 679, 158, 840, 151, 261, 74, 89, 478,
473, 901, 129,
649, 122, 970, 125, 259, 42, 858, 689, 600, 428, 405, 629, 847, 740, 416, 987, 921, 348,
928, 782, 486,
828, 487, 770, 438, 226, 479, 822, 854, 394, 678, 481, 622, 807, 974, 195, 243, 643, 385,
570, 850, 601, 716,
119, 463, 667, 610, 950, 418, 399, 209, 288, 661, 554, 341, 366, 176, 924, 154, 222, 808,
311, 105, 789, 56,
758, 668, 980, 464, 467, 485, 833, 897, 836, 682, 997, 552, 316, 318, 278, 819, 269, 746,
747, 726, 961, 324,
101, 407, 775, 834, 305, 748, 572, 338, 973, 511, 771, 879, 756, 513, 17, 337, 495, 715,
466, 116, 881, 15,
170};

int m = sizeof(arr2) / sizeof(arr2[0]);

trials = 10;
double total_time2 = 0;

for(int i=0; i<trials; i++){


auto start = chrono::high_resolution_clock::now();
bubble_sort(arr2, n);
auto end = chrono::high_resolution_clock::now();
double time_taken2 = chrono::duration_cast<chrono::nanoseconds>(end - start).count();
cout << "Time taken for trial " << i+1 << ": " << time_taken2 / 1e9 << " seconds" <<
endl;
total_time2 += time_taken2;
}
cout<<endl;
double avg_time2 = total_time2 / trials;
cout << "Average time taken for average case " << trials << " trials: " << avg_time2 / 1e9
<< " seconds" << endl;
cout<<endl;

int arr3[250] =
{1997,1993,1984,1979,1970,1969,1967,1960,1946,1930,1919,1910,1908,1898,1889,1885,18
61,1859,
1855,1853,1852,1849,1843,1832,1827,1822,1820,1813,1807,1775,1774,1773,1763,1762,1
756,1754,1746,1741,1738,
1723,1721,1705,1693,1691,1667,1657,1633,1612,1604,1582,1576,1572,1556,1554,1549,1
536,1532,1531,1529,1525,
1514,1508,1504,1503,1483,1481,1472,1467,1461,1459,1455,1437,1434,1430,1427,1415,1
399,1386,1373,1369,1357,
1339,1325,1320,1316,1314,1313,1304,1290,1288,1277,1266,1260,1253,1236,1224,1223,1
216,1213,1202,1192,1186,
1183,1169,1162,1141,1140,1135,1129,1127,1122,1120,1116,1113,1094,1087,1075,1069,1
060,1042,1029,999,990,978,
965,964,955,941,926,925,921,919,907,895,894,886,868,858,849,832,826,813,808,803,795
,775,769,740,738,736,731,
729,725,723,719,715,712,705,700,686,685,676,672,668,666,662,652,646,645,636,633,631
,625,615,607,600,592,590,
584,583,578,554,537,533,529,525,518,506,494,484,481,470,454,441,436,430,425,422,401
,395,388,369,362,347,343,
340,317,312,306,301,300,299,274,265,259,228,224,220,209,205,198,190,188,182,181,167
,150,142,133,125,118,116,
111,110,99,98,90,74,63,53,51,44,41,37,35,33,32,27,22,13};

int p = sizeof(arr3) / sizeof(arr3[0]);

trials = 10;
double total_time3 = 0;

for(int i=0; i<trials; i++){


auto start = chrono::high_resolution_clock::now();
bubble_sort(arr3, n);
auto end = chrono::high_resolution_clock::now();
double time_taken3 = chrono::duration_cast<chrono::nanoseconds>(end - start).count();
cout << "Time taken for trial " << i+1 << ": " << time_taken3 / 1e9 << " seconds" <<
endl;
total_time3 += time_taken3;
}
cout<<endl;
double avg_time3 = total_time3 / trials;
cout << "Average time taken for worst case " << trials << " trials: " << avg_time3 / 1e9 <<
" seconds" << endl;
cout<<endl;

Best case for selection sort


Running time
9.00E-01

8.00E-01

7.00E-01

6.00E-01

5.00E-01

4.00E-01

3.00E-01

2.00E-01

1.00E-01

0.00E+00
0 200 400 600 800 1000 1200

Average case for selection sort

running time
0.9

0.8

0.7

0.6

0.5

0.4

0.3

0.2

0.1

0
0 200 400 600 800 1000 1200 1400 1600
Worst case for selection sort

running time
1.20E-04

1.00E-04

8.00E-05

6.00E-05

4.00E-05

2.00E-05

0.00E+00
0 200 400 600 800 1000 1200 1400 1600

Best case for Insertion sort

running time
9.00E-01

8.00E-01

7.00E-01

6.00E-01

5.00E-01

4.00E-01

3.00E-01

2.00E-01

1.00E-01

0.00E+00
0 200 400 600 800 1000 1200

Average case for Insertion sort


Running time
8.00E-05

7.00E-05

6.00E-05

5.00E-05

4.00E-05

3.00E-05

2.00E-05

1.00E-05

0.00E+00
0 200 400 600 800 1000 1200

Worst case for insertion sort

Y-Values
6.00E-04

5.00E-04

4.00E-04

3.00E-04

2.00E-04

1.00E-04

0.00E+00
0 200 400 600 800 1000 1200 1400 1600

You might also like