Exercise-1
/* Implement recursive linear search and binary search to find a key element in each list of elements. The
elements can be generated using the random number generator*/
//Linear Search
#include<stdio.h>
#include<stdlib.h>
#define N 10
int arr[N];
int linearSearch(int n, int key)
{
if (n < 0) {
return -1;
}
if (arr[n] == key) {
return n;
}
return linearSearch(n - 1, key);
}
int main()
{
for(int i=0;i<N;i++){
arr[i] = rand() % 100 + 1;
}
for(int i=0;i<N;i++){
printf("%d,",arr[i]);
}
printf("Enter your Key");
int key;
scanf("%d",&key);
int pos = linearSearch(N,key);
printf("Key is found at index %d",pos);
return 0;
}
//Binary Search
#include<stdio.h>
#include<stdlib.h>
#define N 10
int arr[N];
int binarySearch(int l, int r, int x)
{
if (r >= l) {
int mid = l + (r - l)/2;
if (x == arr[mid]){
return mid;
}
if (x < arr[mid]){
return binarySearch(l, mid - 1, x);
}
return binarySearch(mid + 1, r, x);
}
return -1;
}
int main()
{
for(int i=0;i<N;i++){
arr[i] = rand() % 10 + 1;
}
for(int i=0;i<N;i++){
printf("%d,",arr[i]);
}
printf("Enter your Key");
int x;
scanf("%d",&x);
int pos = binarySearch(0,N-1,x);
printf("Key is found at index %d",pos);
return 0;
}
Exercise-2
/* Implement Selection sort, Insertion sort, Merge Sort, and Quick Sort algorithms to sort a given set of
elements and determine the time required to sort the elements. Repeat the experiments for different values of
n, the number of elements in the list to be sorted and plot a graph of the time taken versus n. The elements
can be generated using the random number generator*/
//Selection Sort
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int n, arr[10000];
void selectionSort(int n)
{
for (int i=0; i<n-1; i++) {
int minIndex = i;
for (int j=i+1; j<n; j++){
if (arr[j] < arr[minIndex]){
minIndex = j;
}
}
int temp = arr[minIndex];
arr[minIndex] = arr[i];
arr[i] = temp;
}
}
int main()
{
for(int i=1;i<=5;i++)
{
n=i*1000;
arr[n];
clock_t start_t, end_t;
for(int j=0;j<n;j++){
arr[j] = rand() % 10000 + 1;
}
start_t = clock();
selectionSort(n);
end_t = clock();
double timeTaken = (((double)(end_t-start_t))*1000/CLOCKS_PER_SEC);
printf("For array of size %d, time taken to sort is %.2lf ms \n", n, timeTaken);
}
return 0;
}
//Insertion Sort
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int n, arr[10000];
void insertionSort(int n)
{
for (int i=1;i<n;i++){
int key = arr[i];
int j = i-1;
while (j>=0 && arr[j]>key){
arr[j+1] = arr[j];
--j;
}
arr[j+1] = key;
}
}
int main()
{
for(int i=1;i<=5;i++)
{
n=i*1000;
arr[n];
clock_t start_t, end_t;
for(int j=0;j<n;j++){
arr[j] = rand() % 10000 + 1;
}
start_t = clock();
insertionSort(n);
end_t = clock();
double timeTaken = (((double)(end_t-start_t))*1000/CLOCKS_PER_SEC);
printf("For array of size %d, time taken to sort is %.2lf ms \n", n,
timeTaken);
}
return 0;
}
//Merge Sort
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int n, arr[10000];
void merge(int low, int mid, int high)
{
int i, j, k;
int n1 = mid - low + 1;
int n2 = high - mid;
int L[n1], R[n2];
for (i=0; i<n1; i++){
L[i] = arr[low+i];
}
for (j=0; j<n2; j++){
R[j] = arr[mid+j+1];
}
i=0;
j=0;
k=low;
while(i<n1 && j<n2){
if (L[i] <= R[j]){
arr[k] = L[i];
i++;
}
else{
arr[k] = R[j];
j++;
}
k++;
}
while (i < n1){
arr[k] = L[i];
i++;
k++;
}
while (j < n2){
arr[k] = R[j];
j++;
k++;
}
}
void mergeSort(int low, int high)
{
if (low < high){
int mid = low + (high - low) / 2;
mergeSort(low, mid);
mergeSort(mid + 1, high);
merge(low, mid, high);
}
}
int main(){
for(int i=1;i<=5;i++)
{
n=i*1000;
arr[n];
clock_t start_t, end_t;
for(int j=0;j<n;j++){
arr[j] = rand() % 10000 + 1;
}
start_t = clock();
mergeSort(0,n-1);
end_t = clock();
double timeTaken = (((double)(end_t-start_t))*1000/CLOCKS_PER_SEC);
printf("For array of size %d, time taken to sort is %.2lf ms \n", n,
timeTaken);
}
return 0;
}
//Quick sort
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int n, arr[10000];
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int partition(int low, int high)
{
int pivot = arr[high];
int i = low - 1;
for (int j=low; j<high; j++) {
if (arr[j] <= pivot) {
i++;
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i+1], &arr[high]);
return (i+1);
}
void quickSort(int low, int high) {
if (low < high){
int pi = partition(low, high);
quickSort(low, pi - 1);
quickSort(pi + 1, high);
}
}
int main(){
for(int i=1;i<=5;i++)
{
n=i*1000;
arr[n];
clock_t start_t, end_t;
for(int j=0;j<n;j++){
arr[j] = rand() % 10000 + 1;
}
start_t = clock();
quickSort(0,n-1);
end_t = clock();
double timeTaken = (((double)(end_t-start_t))*1000/CLOCKS_PER_SEC);
printf("For array of size %d, time taken to sort is %.2lf ms \n", n,
timeTaken);
}
return 0;
}
Exercise-3
/*Print all the nodes reachable from a given starting node in a digraph using the BFS method*/
//BFS (All reachable nodes from a source)
#include <stdio.h>
int i, j, n, front = -1, rear = -1, visited[10], queue[10], adj[10][10];
void bfs(int v)
{
for (i=1; i<=n; i++){
if (adj[v][i] && !visited[i]){
printf("%d -> %d \n", v, i);
queue[++rear] = i;
}
}
if (front <= rear){
visited[queue[front]] = 1;
bfs(queue[front++]);
}
}
int main()
{
printf("Enter the number of vertices: ");
scanf("%d", &n);
for (i = 1; i <= n; i++){
queue[i] = 0;
visited[i] = 0;
}
printf("Enter graph's adjacency matrix: \n");
for (i=1; i<=n; i++){
for (j=1; j<=n; j++){
scanf("%d", &adj[i][j]);
}
}
int v;
printf("Enter the starting vertex: ");
scanf("%d", &v);
bfs(v);
printf("The node which are reachable are: \n");
for (i=1; i<=n; i++){
if (visited[i]){
printf("%d ", i);
}
}
return 0;
}
Exercise-4
/* Check whether a given graph is connected or not using the DFS method*/
//DFS (Connected graph or not)
#include<stdio.h>
int i, j, n, count=0, reach[10], adj[10][10];
void dfs(int v)
{
reach[v] = 1;
for (i=1; i<=n; i++){
if (adj[v][i] && !reach[i]) {
printf("%d -> %d \n", v, i);
dfs(i);
}
}
}
int main()
{
printf("Enter the number of vertices:");
scanf("%d", &n);
for (i=1; i<=n; i++) {
reach[i] = 0;
}
printf("Enter graph's adjacency matrix: \n");
for (i=1; i<=n; i++){
for (j=1; j<=n; j++){
scanf("%d", &adj[i][j]);
}
}
dfs(1);
for (i=1; i<=n; i++) {
if (reach[i]){
count++;
}
}
if (count == n){
printf("\n Graph is connected");
}
else{
printf("\n Graph is not connected");
}
return 0;
}
Exercise-5
/* Implement the following problems using Decrease & Conquer technique and analyze
their time complexity. (a) Toplogical sorting using DFS */
//DFS (Topological Sort)
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define N 5000
int i, j, n, k=0, reach[N], sortedVertices[N], adj[N][N];
void generateAdjacencyMatrix(int n)
{
for (i=0; i<n; i++){
for (j=0; j<n; j++){
adj[i][j] = 0;
}
}
for (i=0; i<n; i++){
for (j=0; j<i; j++){
adj[i][j] = rand() % 2;
adj[j][i] = 0;
}
}
}
void dfs(int v, int n)
{
reach[v] = 1;
for (i=0; i<n-1; i++) {
if (adj[v][i] && !reach[i]) {
dfs(i, n);
}
}
sortedVertices[++k] = v;
}
void topologicalSort(int n)
{
for (int i=0; i<n; i++) {
reach[i] = 0;
}
for (int i=0; i<n; i++) {
if (!reach[i]) {
dfs(i, n);
}
}
}
int main()
{
for(int i=1;i<=5;i++)
{
n = i*500;
adj[n][n];
clock_t start_t, end_t;
generateAdjacencyMatrix(n);
start_t = clock();
topologicalSort(n);
end_t = clock();
double timeTaken = (((double)(end_t-start_t))*1000/CLOCKS_PER_SEC);
printf("For adjacency matrix of size %d, time taken to topologically sort
is %.2lf ms \n", n, timeTaken);
}
return 0;
}
Exercise-7
/*Implement the 0/1 knapsack problem using Dynamic programming*/
// 0/1 Knapsack Problem (DP)
#include <stdio.h>
int max(int a, int b){
return (a > b) ? a : b;
}
int knapSack(int W, int n, int weight[], int profit[])
{
int i, w, K[n+1][W+1];
for (i=0; i<=n; i++) {
for (w=0; w<=W; w++) {
if (i == 0 || w == 0){
K[i][w] = 0;
}
else if (weight[i-1] <= w) {
K[i][w] = max( profit[i-1] + K[i-1][w-weight[i-1]] , K[i-1][w] );
}
else{
K[i][w] = K[i-1][w];
}
}
}
return K[n][W];
}
int main()
{
int weight[] = { 10, 20, 30 };
int profit[] = { 60, 100, 120 };
int W = 50; //size of Knapsack
int n = 3; //size of profit arrray
printf("Maximum possible profit is %d", knapSack(W, n, weight, profit));
return 0;
}
Exercise-8
//Floyd Algorithm (SpeedUp)
#include<stdio.h>
#include<stdlib.h>
#include<omp.h>
#include<time.h>
#define INF 99999
#define N 500
void floydSequential(int graph[N][N])
{
int i, j, k, distance[N][N];
for (i=0; i<N; i++){
for (j=0; j<N; j++){
distance[i][j] = graph[i][j];
}
}
for (k=0; k<N; k++) {
for (i=0; i<N; i++) {
for (j=0; j<N; j++) {
if (distance[i][j] > distance[i][k] + distance[k][j])
{
distance[i][j] = distance[i][k] + distance[k][j];
}
}
}
}
}
void floydParallel(int graph[N][N])
{
int i, j, k, distance[N][N];
for (i=0; i<N; i++){
for (j=0; j<N; j++){
distance[i][j] = graph[i][j];
}
}
#pragma omp parallel for
for (k=0; k<N; k++) {
#pragma omp parallel for
for (i=0; i<N; i++) {
#pragma omp parallel for
for (j=0; j<N; j++) {
if (distance[i][j] > distance[i][k] + distance[k][j])
{
distance[i][j] = distance[i][k] + distance[k][j];
}
}
}
}
}
int main()
{
int graph[N][N];
clock_t start_t, end_t;
for (int i=0; i<N; i++) {
for (int j=0; j<N; j++) {
if (i == j) {
graph[i][j] = 0;
}
else {
graph[i][j] = rand() % 1000 + 1;
}
}
}
start_t = clock();
floydSequential(graph);
end_t = clock();
double sequentialExecutionTime = end_t-start_t ;
start_t = clock();
floydParallel(graph);
end_t = clock();
double parallelExecutionTime = (double)(end_t-start_t) ;
double speedUp = sequentialExecutionTime / parallelExecutionTime ;
printf("Speed up achieved b/w Sequential and Parallel Floyd Algorithm is
%f",speedUp);
return 0;
}
// If error comes for cc filename.c
// then try cc filename.c -fopenmp
Exercise-9
/*Implement a single source shortest path using Dijkstra’s Algorithm*/
//Dijkstra Algorithm
#include <stdio.h>
#define N 6
#define INF 9999
int minDistance(int distance[], int visited[])
{
int minIndex, min = INF;
for (int v=0; v<N; v++) {
if (!visited[v] && distance[v] <= min) {
min = distance[v];
minIndex = v;
}
}
return minIndex;
}
void dijkstra(int graph[N][N], int source)
{
int distance[N], visited[N];
for (int i=0; i<N; i++) {
distance[i] = INF;
visited[i] = 0;
}
distance[source] = 0;
for (int i=0; i<N-1; i++)
{
int u = minDistance(distance, visited);
visited[u] = 1;
for (int v=0; v<N; v++) {
if (!visited[v] &&
graph[u][v] &&
distance[u] != INF &&
distance[v] > distance[u] + graph[u][v])
{
distance[v] = distance[u] + graph[u][v];
}
}
}
printf("Vertex \t Distance from Source\n");
for (int i=0; i< N; i++) {
printf("%d \t %d\n", i, distance[i]);
}
}
int main() {
int graph[N][N] = {
{0, 4, 0, 0, 0, 0},
{4, 0, 8, 7, 0, 0},
{0, 8, 0, 0, 9, 0},
{0, 7, 0, 0, 0, 10},
{0, 0, 9, 0, 0, 5},
{0, 0, 0, 10, 5, 0}
};
int source = 0;
dijkstra(graph, source);
return 0;
}
Exercise-10
/* Find a subset of a given set S = {Sl, S2, Sn} of n positive integers whose SUM is equal to a given positive
integer d. For example, if S = {1, 2, 5, 6, 8} and d= 9, there are two solutions {1, 2, 6} and {1, 8}. Display a
suitable message if the given problem instance doesn't have a solution */
//Subset problem
#include <stdio.h>
#define N 20
int n, targetSum, set[N], subset[N];
void findSubsets(int index, int currentSum, int subsetSize)
{
if (currentSum == targetSum) {
printf("Subset: {");
for (int i=0; i<subsetSize; i++) {
printf("%d, ", subset[i]);
}
printf(" }\n");
return;
}
if (index == n || currentSum > targetSum) {
return;
}
subset[subsetSize] = set[index];
findSubsets(index + 1, currentSum + set[index], subsetSize + 1);
findSubsets(index + 1, currentSum, subsetSize);
}
int main()
{
printf("Enter the number of elements in set ");
scanf("%d", &n);
printf("Enter the elements of set \n");
for (int i=0; i<n; i++) {
scanf("%d", &set[i]);
}
printf("Enter the target sum ");
scanf("%d", &targetSum);
printf("Subsets that sum to %d \n", targetSum);
findSubsets(0, 0, 0);
return 0;
}