DSA Module 1 To 6
DSA Module 1 To 6
Programming Exercises:
1. In each of the below mentioned scenario, deduce the general formula f(n) where n is the
input size for a given instance of the problem:
a. for(i=0;i<100;i+=2)
statement block;
Ans:
The loop runs from 0 to 100 with a step of 2.
Total iterations = 100/2=50
f(n) = 50 (constant)
b. for(i=1000;i>0;i/=2)
statement block;
Ans:
The loop divides i by 2 until it reaches 0.
Iterations = log2(1000)
f(n) = O(\log n)
c. for(i=0;i<10;i++)
for(j=1; j<10;j*=2)
statement block;
Ans:
Outer loop: 10 iterations.
Inner loop: Iterates for log2(10)
Total iterations = 10⋅log2(10)
f(n) = O(n \log n)
d. for(i=0;i<10;i++)
for(j=0; j<10;j++)
statement block;
Ans:
Outer loop: 10 iterations.
Inner loop: 10 iterations per outer iteration.
Total iterations = 10*10=100
f(n) = O(n^2)
e. for(i=0;i<10;i++)
statement block;
Ans:
Outer loop: 10 iterations.
Inner loop: i+1 iterations for each i.
Total iterations = ∑i=010(i+1)=1+2+3+...+10
=10⋅(10+1) / 2
=55
f(n) = O(n^2)
2. What is a polynomial function and an exponential function? Provide examples in each of
the functions.
Ans:
Polynomial Function:
A function of the form f(n)=an^k+bn^(k−1)+...+c, where k is a
non-negative integer.
Example: f(n)=3n^2+2n+1
Exponential Function:
A function of the form f(n)=a⋅b^n, where b>1.
Example: f(n)=2^n
3. Let f(n)=2^n and g(n)=n^2. Compare the values of f(n) and g(n) for n=1 to n, and provide
the conclusion on the rate of increase among them.
Ans:
Calculations for f(n) and g(n) :
n f(n) = 2^n g(n) = n^2
1 2 1
2 4 4
3 8 9
4 16 16
5 32 25
6 64 36
7 128 49
8 256 64
9 512 81
10 1024 100
Observations:
1. At smaller values of n (e.g., n=1 and n=2), f(n) and g(n) are close, and g(n) might
even surpass f(n) temporarily.
2. From n=5 onwards, f(n) = 2^n grows much faster than g(n) = n^2, and this trend
continues as n increases.
Conclusion:
● The growth rate of f(n)=2^n = 2^n is exponential, while the growth rate of g(n) =
n^2 is polynomial.
● Exponential growth outpaces polynomial growth as n increases. Hence, f(n) will
eventually become much larger than g(n), regardless of how large g(n) is initially.
Review Questions
1. What are arrays and why are they needed?
Ans:
● An array is a data structure that stores a collection of elements of the
same data type in contiguous memory locations.
● Each element in an array can be accessed using an index, starting from
0.
● Example:
int numbers[5] = {10, 20, 30, 40, 50};
Why are Arrays Needed?
● Efficient storage for multiple values under one name.
● Allows easy access using indexes.
● Supports iterative operations and forms the base for advanced structures
like stacks and queues.
Row-Major Order:
Rows are stored one after another.
Address of A [i][j]:
Base Address + ( i × Number of columns + j ) × size of each element
Base Address + ( i × Number of columns + j ) × size of each element
Column-Major Order:
Columns are stored one after another.
Address of A [i][j]:
Base Address + ( j × Number of rows + i ) × size of each element
Base Address + ( j × Number of rows + i ) × size of each element
Coordinate list (COO) stores the row and column indices of each
non-zero element along with the value.
8. For an array declared as int arr[50], Calculate the address of arr [35], if base (arr) = 1000
and w=2.
Ans:
Given:
Base Address = 1000
Word Size = 2 bytes
Array size = 50 elements
To calculate the address of arr[35], we use the formula:
Address of arr[35]=Base Address+35×Size of element
Address of arr[35]=1000+35×2=1000+70=1070
So, the address of arr[35] is 1070.
9. Consider a 2 dimensional array Marks [10[[15] having its base address as 2000 and the
number of bytes per element of the array is 2. Now, compute the address of the element,
Marks [8][5], assuming that the elements are stored in row major order.
Ans:
Given:
Base Address = 2000
Number of rows = 10, Number of columns = 15
Size of element = 2 bytes
We are using row-major order.
To calculate the address of Marks[8][5], use the formula for
row-major order:
Address of Marks[i][j] = Base Address + ( ( i × Number of columns
) + j ) × Size of element
Substituting the values:
Address of Marks[8][5]=2000+((8×15)+5)×2
=2000+(120+5)×2
=2000+250
=2250
So, the address of Marks[8][5] is 2250.
10. How are arrays related to pointers?
Ans:
13. Consider a two-dimensional array arr[10][10] which has base address = 1000 and the
number of | bytes per element of the array = 2. Now, compute the address of the
element arr[8][5] assuming that the elements are stored in column major order.
Ans:
Given:
Base Address = 1000
Array Size = 10x10 (2D array arr[10][10])
Size of Element = 2 bytes
Stored in Column-Major Order
In column-major order, the elements of each column are stored one
after another. The address of an element arr[i][j] is computed as:
Address of arr[i][j]=Base Address+((j×Number of rows)+i)×Size of
element
For arr[8][5]:
Address of arr[8][5]=1000+((5×10)+8)×2
=1000+(50+8)×2
=1000+116
=1116
So, the address of arr[8][5] is 1116.
14. Consider the array given below:
Name[0] | Adam
Name[1] | Charles
Name[2] | Dicken
Name([3] Esha
Name[4] | Georgia
Name[5] | Hillary
Name[6] | Mishael
a. How many elements would be moved if the name Andrew has to be added in it?
(i) 7 (ii) 4 (iii) 5 (iv) 6
b. How many elements would be moved if the name Esha has to be deleted from
it?
(i) 3 (ii) 4 (iii) 5 (iv) 6
Programming Exercises:
1. Consider an array MARKS[ 201 5] which stores the ‘marks obtained by 20
students in 5 subjects. Now
write a program to
a. find the average marks obtained in each subject.
b. find the average marks obtained by every student.
c. find the number of students who have scored below 50 in their average.
d. display the scores obtained by every student.
Ans:
#include <stdio.h>
int main()
{
int MARKS[20][5], i, j;
float avgSubject[5], avgStudent[20];
int below50 = 0;
return 0;
}
2. Write a program that reads an array of 100 integers. Display all the pairs of
elements whose sum is 50.
Ans:
#include <stdio.h>
int main() {
int arr[100], i, j;
for(i = 0; i < 100; i++) {
scanf("%d", &arr[i]);
}
for(i = 0; i < 99; i++) {
for(j = i+1; j < 100; j++) {
if(arr[i] + arr[j] == 50) {
printf("Pair: (%d, %d)\n", arr[i], arr[j]);
}
}
}
return 0;
}
3. Write a program to interchange the second element with the second last element.
Ans:
#include <stdio.h>
int main()
{
int arr[100], temp;
for(int i = 0; i < 100; i++) {
scanf("%d", &arr[i]);
}
temp = arr[1];
arr[1] = arr[98];
arr[98] = temp;
for(int i = 0; i < 100; i++) {
printf("%d ", arr[i]);
}
return 0;
}
int main()
{
int arr[100], sumOfSquares = 0;
for(int i = 0; i < 100; i++) {
scanf("%d", &arr[i]);
}
for(int i = 0; i < 100; i++) {
sumOfSquares += arr[i] * arr[i];
}
printf("Sum of squares: %d\n", sumOfSquares);
return 0;
}
int main()
{
int arr[10][10], i, j, sum = 0, count = 0;
float mean;
for(i = 0; i < 10; i++) {
for(j = 0; j < 10; j++) {
scanf("%d", &arr[i][j]);
sum += arr[i][j];
count++;
}
}
mean = (float)sum / count;
printf("Sum: %d\nMean: %.2f\n", sum, mean);
return 0;
}
7. Write a program that computes the sum of the elements that are stored on the
main diagonal of a matrix using pointers.
Ans:
#include <stdio.h>
int main()
{
int arr[3][3], *ptr, sum = 0;
ptr = &arr[0][0];
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
scanf("%d", ptr++);
}
}
ptr = &arr[0][0];
for(int i = 0; i < 3; i++) {
sum += *(ptr + i*3 + i);
}
printf("Sum of main diagonal: %d\n", sum);
return 0;
}
int main()
{
int A[3][3], B[3][3], C[3][3], *ptrA, *ptrB, *ptrC;
ptrA = &A[0][0];
ptrB = &B[0][0];
for(int i = 0; i < 9; i++) {
scanf("%d", ptrA++);
scanf("%d", ptrB++);
}
ptrA = &A[0][0];
ptrB = &B[0][0];
ptrC = &C[0][0];
for(int i = 0; i < 9; i++) {
*ptrC = *ptrA + *ptrB;
ptrA++;
ptrB++;
ptrC++;
}
ptrC = &C[0][0];
for(int i = 0; i < 9; i++) {
printf("%d ", *ptrC++);
if ((i + 1) % 3 == 0) printf("\n");
}
return 0;
}
9. Write a program that computes the product of the elements that are stored on the
diagonal above the main diagonal.
Ans:
#include <stdio.h>
int main()
{
int arr[3][3], product = 1;
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
scanf("%d", &arr[i][j]);
}
}
for(int i = 0; i < 2; i++) {
for(int j = i + 1; j < 3; j++) {
product *= arr[i][j];
}
}
10. Write a program to count the total number of non zero elements in a
two-dimensional array.
Ans:
#include <stdio.h>
int main()
{
int arr[3][3], count = 0;
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
scanf("%d", &arr[i][j]);
}
}
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
if(arr[i][j] != 0) count++;
}
}
int main()
{
int arr[3][3], odd[9], even[9], oddCount = 0, evenCount = 0;
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
scanf("%d", &arr[i][j]);
}
}
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
if(arr[i][j] % 2 == 0)
even[evenCount++] = arr[i][j];
else
odd[oddCount++] = arr[i][j];
}
}
printf("Odd elements: ");
for(int i = 0; i < oddCount; i++) {
printf("%d ", odd[i]);
}
printf("\nEven elements: ");
for(int i = 0; i < evenCount; i++) {
printf("%d ", even[i]);
}
return 0;
}
12. Write a program to read two floating point number arrays. Merge the two arrays
and display the resultant array in reverse order.
Ans:
#include <stdio.h>
int main()
{
float arr1[5], arr2[5], merged[10];
int i, j = 0;
for(i = 0; i < 5; i++) scanf("%f", &arr1[i]);
for(i = 0; i < 5; i++) scanf("%f", &arr2[i]);
for(i = 0; i < 5; i++) merged[j++] = arr1[i];
for(i = 0; i < 5; i++) merged[j++] = arr2[i];
for(i = 9; i >= 0; i--) {
printf("%.2f ", merged[i]);
}
return 0;
}
13. Write a program using pointers to interchange the second biggest and the
second smallest in the array.
Ans:
#include <stdio.h>
#include <limits.h>
int main()
{
int arr[10], *ptr, secondMax = INT_MIN, secondMin =
INT_MAX, max = INT_MIN, min = INT_MAX, maxIdx,
minIdx;
for(int i = 0; i < 10; i++) scanf("%d", &arr[i]);
for(int i = 0; i < 10; i++) {
if(arr[i] > max) {
secondMax = max;
max = arr[i];
} else if(arr[i] > secondMax && arr[i] < max) {
secondMax = arr[i];
maxIdx = i;
}
if(arr[i] < min) {
secondMin = min;
min = arr[i];
} else if(arr[i] < secondMin && arr[i] > min) {
secondMin = arr[i];
minIdx = i;
}
}
ptr = arr + maxIdx;
*ptr = secondMin;
ptr = arr + minIdx;
*ptr = secondMax;
for(int i = 0; i < 10; i++) {
printf("%d ", arr[i]);
}
return 0;
}
14. Write a menu driven program to read and display a p* q * r matrix, Also, find the
sum, transpose, and product of the two p*q*r matrices.
15. Write a program that reads a matrix and displays the sum of its diagonal
elements.
Ans:
#include <stdio.h>
int main()
{
int arr[3][3], sum = 0;
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
scanf("%d", &arr[i][j]);
}
}
for(int i = 0; i < 3; i++) {
sum += arr[i][i];
}
int main() {
int arr[3][3], sum = 0;
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
scanf("%d", &arr[i][j]);
}
}
for(int i = 0; i < 3; i++) {
for(int j = i + 1; j < 3; j++) {
sum += arr[i][j];
}
}
printf("Sum of elements above main diagonal: %d\n", sum);
return 0;
}
17. Write a program that reads a matrix and displays the sum of the elements below
the main diagonal.
(Hint: Calculate the sum of elements Aij where i>j)
Ans:
#include <stdio.h>
int main() {
int n, i, j, sum = 0;
scanf("%d", &n);
int a[n][n];
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
scanf("%d", &a[i][j]);
for (i = 1; i < n; i++)
for (j = 0; j < i; j++)
sum += a[i][j];
printf("%d\n", sum);
return 0;
}
18. Write a program that reads a square matrix of size n * n. Write a function int
isUpperTriangular (int a[](], int n) that returns | if the matrix is upper triangular.
(Hint: Array A is upper triangular ifA,, = 0 and i<j)
Ans:
#include <stdio.h>
int isUpperTriangular(int a[][100], int n) {
for (int i = 1; i < n; i++)
for (int j = 0; j < i; j++)
if (a[i][j] != 0)
return 0;
return 1;
}
int main() {
int n;
scanf("%d", &n);
int a[100][100];
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
scanf("%d", &a[i][j]);
if (isUpperTriangular(a, n))
printf("Upper Triangular\n");
else
printf("Not Upper Triangular\n");
return 0;
}
19. Write a program that reads a square matrix of size nxn. Write a function int
isLowerTriangular (int a[][], int n) that returns 1 if the matrix is lower triangular.
(Hint: Array a is lower triangular if A, = 0 and i<j)
Ans:
#include <stdio.h>
int main() {
int n;
scanf("%d", &n);
int a[100][100];
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
scanf("%d", &a[i][j]);
if (isLowerTriangular(a, n))
printf("Lower Triangular\n");
else
printf("Not Lower Triangular\n");
return 0;
}
20. Write a program that reads a square matrix of size nxn. Write a function int
isSymmetric (int a[][], int n) that returns 1 if the matrix symmetric
(Hint: Array A is symmetric if A, = A, for all values of i and j)
Ans:
#include <stdio.h>
int main() {
int n;
scanf("%d", &n);
int a[100][100];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
scanf("%d", &a[i][j]);
}
}
if (isSymmetric(a, n)) {
printf("Symmetric\n");
} else {
printf("Not Symmetric\n");
}
return 0;
}
21. Write a program to calculate XA + YB where A and B are matrices and X=2 and
Y=3.
Ans:
#include <stdio.h>
int main()
{
int n, i, j, X = 2, Y = 3;
scanf("%d", &n);
int A[n][n], B[n][n], C[n][n];
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
scanf("%d", &A[i][j]);
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
scanf("%d", &B[i][j]);
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
C[i][j] = X * A[i][j] + Y * B[i][j];
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++)
printf("%d ", C[i][j]);
printf("\n");
}
return 0;
}
22. Write a program to illustrate the use of a pointer that points to a 2D array.
Ans:
#include <stdio.h>
int main()
{
int n, i, j;
scanf("%d", &n);
int a[n][n], (*p)[n] = a;
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
scanf("%d", &p[i][j]);
for (i = 0; i < n; i++, printf("\n"))
for (j = 0; j < n; j++)
printf("%d ", p[i][j]);
return 0;
}
23. Write a program to enter a number and break it into n number of digits.
Ans:
#include <stdio.h>
int main()
{
int n;
scanf("%d", &n);
while (n) {
printf("%d ", n % 10);
n /= 10;
}
return 0;
}
24. Write a program to delete all the duplicate entries from an array of n integers.
Ans:
#include <stdio.h>
int main()
{
int n, i, j, k;
scanf("%d", &n);
int a[n];
for (i = 0; i < n; i++)
scanf("%d", &a[i]);
for (i = 0; i < n; i++)
for (j = i + 1; j < n;)
if (a[i] == a[j]) {
for (k = j; k < n - 1; k++) a[k] = a[k + 1];
n--;
} else j++;
for (i = 0; i < n; i++) printf("%d ", a[i]);
return 0;
}
25. Write a program to read a floating point array. Update the array to insert a new
number at the specified location.
Ans:
#include <stdio.h>
int main()
{
int n, pos, i;
float num;
scanf("%d", &n);
float a[n + 1];
for (i = 0; i < n; i++)
scanf("%f", &a[i]);
scanf("%f%d", &num, &pos);
for (i = n; i > pos; i--)
a[i] = a[i - 1];
a[pos] = num;
for (i = 0; i <= n; i++)
printf("%.2f ", a[i]);
return 0;
}
Review Questions
3. Define data structures. Give some examples.
4. In how many ways can you categorize data structures? Explain each of them.
5. Discuss the applications of data structures.
6. Write a short note on different operations that can be performed on data structures.
7. Compare a linked list with an array.
8. Write a short note on abstract data type.
9. Explain the different types of data structures. Also discuss their merits and demerits.
10. Define an algorithm. Explain its features with the help of suitable examples.
11. Explain and compare the approaches for designing an algorithm.
12. What is modularization? Give its advantages.
13. Write a brief note on trees as a data structure.
14. What do you understand by a graph?
15. Explain the criteria that you will keep in mind while choosing an appropriate algorithm
to solve a particular problem.
16. What do you understand by time–space trade-off?
17. What do you understand by the efficiency of an algorithm?
18. How will you express the time complexity of a given algorithm?
19. Discuss the significance and limitations of the Big O notation.
20. Discuss the best case, worst case, average case, and amortized time complexity of
an algorithm.
21. Categorize algorithms based on their running time complexity.
22. Give examples of functions that are in Big O notation as well as functions that are not
in Big O notation.
23. Explain the little o notation.
24. Give examples of functions that are in little o notation as well as functions that are
not in little o notation.
25. Differentiate between Big O and little o notations.
26. Explain the Ω notation.
27. Give examples of functions that are in Ω notation as well as functions that are not in
Ω notation.
28. Explain the Θ notation.
29. Give examples of functions that are in Θ notation as well as functions that are not in
Θ notation.
Programming Exercises:
1. In each of the below mentioned scenario, deduce the general formula f(n) where n is the
input size for a given instance of the problem:
a. for(i=0;i<100;i+=2)
statement block;
Ans:
The loop runs from 0 to 100 with a step of 2.
Total iterations = 100/2=50
f(n) = 50 (constant)
b. for(i=1000;i>0;i/=2)
statement block;
Ans:
The loop divides i by 2 until it reaches 0.
Iterations = log2(1000)
f(n) = O(\log n)
c. for(i=0;i<10;i++)
for(j=1; j<10;j*=2)
statement block;
Ans:
Outer loop: 10 iterations.
Inner loop: Iterates for log2(10)
Total iterations = 10⋅log2(10)
f(n) = O(n \log n)
d. for(i=0;i<10;i++)
for(j=0; j<10;j++)
statement block;
Ans:
Outer loop: 10 iterations.
Inner loop: 10 iterations per outer iteration.
Total iterations = 10*10=100
f(n) = O(n^2)
e. for(i=0;i<10;i++)
statement block;
Ans:
Outer loop: 10 iterations.
Inner loop: i+1 iterations for each i.
Total iterations = ∑i=010(i+1)=1+2+3+...+10
=10⋅(10+1) / 2
=55
f(n) = O(n^2)
2. What is a polynomial function and an exponential function? Provide examples in each of
the functions.
Ans:
Polynomial Function:
A function of the form f(n)=an^k+bn^(k−1)+...+c, where k is a
non-negative integer.
Example: f(n)=3n^2+2n+1
Exponential Function:
A function of the form f(n)=a⋅b^n, where b>1.
Example: f(n)=2^n
3. Let f(n)=2^n and g(n)=n^2. Compare the values of f(n) and g(n) for n=1 to n, and provide
the conclusion on the rate of increase among them.
Ans:
Calculations for f(n) and g(n) :
n f(n) = 2^n g(n) = n^2
1 2 1
2 4 4
3 8 9
4 16 16
5 32 25
6 64 36
7 128 49
8 256 64
9 512 81
10 1024 100
Observations:
1. At smaller values of n (e.g., n=1 and n=2), f(n) and g(n) are close, and g(n) might
even surpass f(n) temporarily.
2. From n=5 onwards, f(n) = 2^n grows much faster than g(n) = n^2, and this trend
continues as n increases.
Conclusion:
● The growth rate of f(n)=2^n = 2^n is exponential, while the growth rate of g(n) =
n^2 is polynomial.
● Exponential growth outpaces polynomial growth as n increases. Hence, f(n) will
eventually become much larger than g(n), regardless of how large g(n) is initially.
Review Questions
1. What do you understand by stack overflow and underflow?
2. Differentiate between an array and a stack.
3. How does a stack implemented using a linked list differ from a stack implemented using
an array?
4. Differentiate between peek () and pop() functions.
5. Why are parentheses not required in postfix/prefix expressions?
6. Explain how stacks are used in a non-recursive program?
7. What do you understand by a multiple stack? How is it useful?
8. Explain the terms infix expression, prefix expression, and postfix expression. Convert the
following infix expressions to their postfix equivalents:
(a) A-B+C
(b) A*B+C/D
(c) (A-B)+C*D/E-C
(d) (A*B) + (C/D) - (D+E)
(e) (A-B)+D/(E+F)*G)
(f) (A - 2*B+C)/D*E)+F
(g) 14/7%3-4+9/2
9. Convert the following infix expressions to their postfix equivalents:
(a) A-B+C
(b) A*B+C/D
(c) (A-B)+C*D/E-C
(d) (A*B)+(C/D)-(D+E)
(e) (A-B)+D/(E+F)*G))
(f) (A-2*B+C)/D*E)+F
(g) 14/7%3-4+9/2
10. Find the infix equivalents of the following postfix equivalents:
(a) AB+C*D- (b) ABC*+D-
11. Give the infix expression of the following prefix expressions.
a. *-+ABCD b. +-a*BCD
12. Convert the expression given below into its corresponding postfix expression and then
evaluate it. Also write a program to evaluate a postfix expression.
10 +((7—5)+ 10)/2
13. Write a function that accepts two stacks. Copy the contents of the first stack in the
second stack. Note that the order of elements must be preserved. (Hint: use a temporary
stack)
14. Draw the stack structure in each case when the following
operations are performed on an empty stack.
(a) Add A,B,C.D,E,F
(b) Delete two letters
(c) Add G
(d) Add H
(e) Delete four letters
(f) Add I
15. Differentiate between an iterative function and a recursive function. Which one will you
prefer to use and in what circumstances? Explain the Tower of Hanoi problem.
16. Explain the Tower of Hanoi problem.
Answers
● Stack Overflow occurs when there is no more space to push new elements onto the
stack because it has exceeded its capacity. This happens when the stack reaches its
maximum limit.
● Stack Underflow happens when there is an attempt to pop an element from an empty
stack, which doesn't have any elements to remove.
Structure A linear data structure. A linear data structure, but follows LIFO
(Last In, First Out) principle.
Insertion/Deletion Can insert or delete at any Can only insert (push) at the top and
position. remove (pop) from the top.
3. How does a stack implemented using a linked list differ from a stack
implemented using an array?
● peek(): This function returns the top element of the stack without removing it.
● pop(): This function removes and returns the top element of the stack.
In postfix and prefix expressions, the order of operations is already defined due
to the position of operators relative to operands. The placement of operators in these
expressions ensures that the operations are carried out in the correct order, making
parentheses unnecessary.
Stacks are used in non-recursive programs to simulate the function call stack manually.
For example, when solving problems like tree traversals, expression evaluation, or
depth-first search, a stack can be used to store intermediate states instead of relying on
recursion.
A multiple stack refers to having multiple stacks within a single data structure, such as
a fixed-size array or memory block. It's useful when you want to manage multiple
collections of data (stacks) but need to use a single contiguous memory space. This is
typically implemented by dividing a memory block into segments for each stack.
Conversion to Postfix:
(a) A - B + C → A B - C +
(b) A * B + C / D → A B * C D / +
(c) (A - B) + C * D / E - C → A B - C D * E / + C -
(d) (A * B) + (C / D) - (D + E) → A B * C D / + D E + -
(e) (A - B) + D / (E + F) * G → A B - D E F + / G * +
(f) (A - 2 * B + C) / D * E + F → A 2 B * - C + D / E * F +
(g) 14 / 7 % 3 - 4 + 9 / 2 → 14 7 / 3 % 4 - 9 2 / +
(a) A - B + C → A B - C +
(b) A * B + C / D → A B * C D / +
(c) (A - B) + C * D / E - C → A B - C D * E / + C -
(d) (A * B) + (C / D) - (D + E) → A B * C D / + D E + -
(e) (A - B) + D / (E + F) * G → A B - D E F + / G * +
(f) (A - 2 * B + C) / D * E + F → A 2 B * - C + D / E * F +
(g) 14 / 7 % 3 - 4 + 9 / 2 → 14 7 / 3 % 4 - 9 2 / +
(a) AB + C * D - → (A + B) * C - D
(b) ABC * + D - → A + (B * C) - D
(a) *-+ABCD
○ Infix Expression: (A + B) * (C - D)
(b) +-a*BCD
○ Infix Expression: a + (B * C) - D
12. Convert the expression given below into its corresponding postfix
expression and then evaluate it. Also, write a program to evaluate a postfix
expression.
Postfix Expression:
10 7 5 - 10 + 2 / +
Evaluation:
1. 10 7 5 - → 7 - 5 = 2 → 10 2 10 + 2 / +
2. 10 2 10 + → 2 + 10 = 12 → 10 12 2 / +
3. 10 12 2 / → 12 / 2 = 6 → 10 6 +
4. 10 6 + → 10 + 6 = 16
Result: 16
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX 50
int stack[MAX];
int top = -1;
int pop() {
if (top == -1) {
printf("Stack Underflow\n");
return -1;
} else {
return stack[top--];
}
}
int main() {
char expression[] = "10 7 5 - 10 + 2 / +";
printf("Result: %d\n", evaluatePostfix(expression));
return 0;
}
13. Write a function that accepts two stacks. Copy the contents of the first
stack in the second stack. Note that the order of elements must be
preserved. (Hint: use a temporary stack)
#include <stdio.h>
#include <stdlib.h>
#define MAX 50
printf("Stack 1: ");
displayStack(stack1, top1);
return 0;
}
14. Draw the stack structure in each case when the following operations are
performed on an empty stack.
(a) Add A, B, C, D, E, F
Stack after each operation:
Push A → [A]
Push B → [A, B]
Push C → [A, B, C]
Push D → [A, B, C, D]
Push E → [A, B, C, D, E]
Push F → [A, B, C, D, E, F]
Pop → [A, B, C, D, E]
Pop → [A, B, C, D]
(c) Add G
Push G → [A, B, C, D, G]
(d) Add H
Push H → [A, B, C, D, G, H]
(f) Add I
Push I → [A, I]
Definition Uses loops (for, while) for Calls itself to solve a problem.
repeated execution.
Memory Uses constant memory for Uses memory for each function call,
Usage execution. leading to a stack overflow risk.
Performance Generally more efficient, avoids Can be slower due to function call
overhead of multiple function overhead.
calls.
When to Use Preferred when the problem can Preferred when the problem is naturally
be easily solved using loops. recursive (e.g., tree traversals,
factorials).
The Tower of Hanoi is a classic problem in computer science that involves three rods
and a number of disks of different sizes. The objective is to move all disks from the
source rod to the target rod, following these rules:
● Move n-1 disks from the source rod to the auxiliary rod.
● Move the nth disk to the target rod.
● Move n-1 disks from the auxiliary rod to the target rod.
The minimum number of moves required to solve the Tower of Hanoi problem is 2^n -
1, where n is the number of disks.
Programming Exercises
1. Write a program to implement a stack using a linked list.
2. Write a program to convert the expression “a+b” into “ab+".
3. Write a program to convert the expression “a+b” into “+ab”.
4. Write a program to implement a stack that stores names of students in the class.
5. Write a program to input two stacks and compare their contents.
Answers
int pop() {
if (!top) return -1;
Node* temp = top;
int value = temp->data;
top = top->next;
free(temp);
return value;
}
int main() {
push(10); push(20);
printf("Popped: %d\n", pop());
return 0;
}
int main() {
char infix[] = "a+b", postfix[4];
postfix[0] = infix[0];
postfix[1] = infix[2];
postfix[2] = infix[1];
postfix[3] = '\0';
printf("Postfix: %s\n", postfix);
return 0;
}
int main() {
char infix[] = "a+b", prefix[4];
prefix[0] = infix[1];
prefix[1] = infix[0];
prefix[2] = infix[2];
prefix[3] = '\0';
printf("Prefix: %s\n", prefix);
return 0;
}
int main() {
push("Alice"); push("Bob");
printf("Top: %s\n", top->name);
}
int main() {
Node *s1 = NULL, *s2 = NULL;
printf("Stacks are %s\n", compare(s1, s2) ? "equal" : "not
equal");
return 0;
}
int main() {
push(10);
push(20); }
2. Pop Operation (Delete Element from Stack)
#include <stdio.h>
#define SIZE 5
int pop() {
if (top == -1) {
printf("Stack Underflow\n");
return -1;
}
return stack[top--];
}
int main() {
push(10); push(20);
printf("Popped: %d\n", pop());
return 0;
}
int main() {
push(10); push(20);
printf("Topmost element: %d\n", peep());
return 0;
}
void display() {
if (top == -1) {
printf("Stack is empty\n");
return;
}
for (int i = top; i >= 0; i--)
printf("%d ", stack[i]);
printf("\n");
}
int main() {
push(10); push(20); push(30);
printf("Stack: ");
display();
return 0;
}
int main() {
push(10);
push(20); }
2. Pop Operation (Delete Element from Stack Using Linked List)
#include <stdio.h>
#include <stdlib.h>
int pop() {
if (!top) {
printf("Stack Underflow\n");
return -1;
}
Node* temp = top;
int value = temp->data;
top = top->next;
free(temp);
return value;
}
int main() {
push(10); push(20);
printf("Popped: %d\n", pop());
return 0;
}
3. Peep Operation (Return Topmost Element Without Deleting)
#include <stdio.h>
#include <stdlib.h>
int peep() {
if (!top) {
printf("Stack is empty\n");
return -1;
}
return top->data;
}
int main() {
push(10); push(20);
printf("Topmost element: %d\n", peep());
}
void display() {
if (!top) {
printf("Stack is empty\n");
return;
}
Node* temp = top;
while (temp) {
printf("%d ", temp->data);
temp = temp->next;
}
printf("\n");
}
int main() {
push(10); push(20); push(30);
printf("Stack: ");
display();
return 0;
}
Review Questions
1. What is a priority queue? Give its applications.
2. Explain the concept of a circular queue? How is it better than a linear queue?
3. Why do we use multiple queues?
4. Draw the queue structure in each case when the following operations are performed
on an empty queue.
(a) Add A,B,C,D,E.F
(b) Delete two letters
(c) Add G (d) Add H
(e) Delete four letters (f) Add I
5. Consider the queue given below which has FRONT = 1 and REAR = 5.
| |A|B|C|D|E| | | | |
Now perform the following operations on the queue:
(a) Add F (b) Delete two letters
(c) Add G (d) Add H
(e) Delete four letters (f) Add I
6. Consider the dequeue given below which has LEFT = 1 and RIGHT = 5.
| |A|B|C|D|E| | | | |
Now perform the following operations on the queue:
(a) Add F on the left
(b) Add G on the right
(c) Add H on the right
(d) Delete two letters from left
(e) Add I on the right () Add J on the left
(g) Delete two letters from right
Answers
1. What is a Priority Queue? Applications
A priority queue is a data structure where each element is associated with a priority.
Elements with higher priority are dequeued before elements with lower priority.
Applications:
● CPU scheduling
● Dijkstra's shortest path algorithm
● Huffman coding
● Event simulation
A circular queue is a queue in which the last position is connected back to the first
position, forming a circle.
Advantages over Linear Queue:
● Efficient use of space: No unused slots even after dequeue.
● Prevents "Queue Full" when space is available in earlier positions.
6. Dequeue Operations
int count() {
return (rear - front + 1);
}
int main() {
front = 0; rear = 4; // Example
printf("Number of items: %d\n", count());
return 0;
}
int main() {
for (int i = 1; i <= 10; i++) enqueue(i);
printf("Queue created with 10 values\n");
return 0;
}
int main() {
insertRear(10); insertFront(20);
printf("Inserted at both ends\n");
return 0;
}
int dequeue() {
if (!front) return -1;
Node* temp = front;
int value = temp->data;
front = front->next;
free(temp);
return value;
}
int main() {
enqueue(10); enqueue(20);
printf("Dequeued: %d\n", dequeue());
return 0;
}
int main() {
enqueue(10); enqueue(20);
printf("Inserted at rear vacant locations\n");
return 0;
}
void deleteFront() {
if (front == rear) printf("Queue Underflow\n");
else front++;
}
void deleteRear() {
if (front == rear) printf("Queue Underflow\n");
else rear--;
}
int main() {
deleteFront(); deleteRear();
printf("Deleted from both ends\n");
return 0;
}
int main() {
printf("Implemented insertion and deletion at both ends\n");
return 0;
}
8. Priority Queue
c
Copy code
#include <stdio.h>
#include <stdlib.h>
int main() {
enqueue(10, 2); enqueue(20, 1);
printf("Priority Queue created\n");
return 0;
}
int dequeue() {
if (!stack2) {
while (stack1) {
Node* temp = stack1;
int value = temp->data;
stack1 = stack1->next;
enqueue(value); // Reverse
}
}
int value = stack2->data;
Node* temp = stack2;
}
int main() {
enqueue(10); enqueue(20);
Node* stack = NULL;
while (front) push(&stack, dequeue());
printf("Converted Queue to Stack\n");
return 0;
}
void reverse() {
Node *prev = NULL, *curr = front, *next = NULL;
rear = front;
while (curr) {
next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
front = prev;
}
int main() {
enqueue(10); enqueue(20); enqueue(30);
reverse();
printf("Reversed the Queue\n");
return 0;
}
int main() {
Node *q1 = NULL, *q2 = NULL; // Example linked lists
printf("Queues are %s\n", compare(q1, q2) ? "Equal" : "Not
Equal");
return 0;
}
int main() {
enqueue(10);
enqueue(20);
enqueue(30);
return 0;
}
int dequeue() {
if (front == -1 || front > rear) {
printf("Queue Underflow\n");
return -1;
} else {
return queue[front++];
}
}
int main() {
front = 0; rear = 2; // Assume queue has 3 elements:
10, 20, 30
queue[0] = 10; queue[1] = 20; queue[2] = 30;
printf("Dequeued: %d\n", dequeue());
printf("Dequeued: %d\n", dequeue());
return 0;
}
3. Peep Operation (Return Front Element without Deletion)
#include <stdio.h>
#define SIZE 10
int peep() {
if (front == -1 || front > rear) {
printf("Queue is Empty\n");
return -1;
} else {
return queue[front];
}
}
int main() {
front = 0; rear = 2;
queue[0] = 10; queue[1] = 20; queue[2] = 30;
printf("Front Element: %d\n", peep());
return 0;
}
void display() {
if (front == -1 || front > rear) {
printf("Queue is Empty\n");
} else {
printf("Queue Elements: ");
for (int i = front; i <= rear; i++) {
printf("%d ", queue[i]);
}
printf("\n");
}
}
int main() {
front = 0; rear = 2; // Assume queue has 3 elements:
10, 20, 30
queue[0] = 10; queue[1] = 20; queue[2] = 30;
display();
return 0;
}
int main() {
enqueue(10);
enqueue(20);
enqueue(30);
return 0;
}
int dequeue() {
if (front == NULL) {
printf("Queue Underflow\n");
return -1;
}
Node* temp = front;
int value = temp->data;
front = front->next;
if (front == NULL) rear = NULL; // Queue becomes empty
free(temp);
return value;
}
int main() {
enqueue(10); enqueue(20); enqueue(30);
printf("Dequeued: %d\n", dequeue());
printf("Dequeued: %d\n", dequeue());
return 0;
}
int peep() {
if (front == NULL) {
printf("Queue is Empty\n");
return -1;
}
return front->data;
}
int main() {
enqueue(10); enqueue(20); enqueue(30);
printf("Front Element: %d\n", peep());
return 0;
}
4. Display Elements of Queue using Linked List
#include <stdio.h>
#include <stdlib.h>
void display() {
if (front == NULL) {
printf("Queue is Empty\n");
return;
}
Node* temp = front;
printf("Queue Elements: ");
while (temp != NULL) {
printf("%d ", temp->data);
temp = temp->next;
}
printf("\n");
}
int main() {
enqueue(10); enqueue(20); enqueue(30);
display();
return 0;
}
Circular Queue:
1. Write a program to insert an element into the circular queue.
2. Write a program to delete an element from a circular queue.
3. Write a program to return the value of the FRONT element of the circular
queue(without deleting it from the queue).
4. Write a program to display the elements of a circular queue.
Answers
1. Insert Operation (Enqueue in Circular Queue)
#include <stdio.h>
#define SIZE 5
int queue[SIZE];
int front = -1, rear = -1;
int main() {
enqueue(10);
enqueue(20);
enqueue(30);
return 0;
}
int queue[SIZE];
int front = -1, rear = -1;
int dequeue() {
if (front == -1) {
printf("Queue Underflow\n");
return -1;
} else {
int value = queue[front];
if (front == rear) {
front = rear = -1; // Queue becomes empty
} else {
front = (front + 1) % SIZE;
}
return value;
}
}
int main() {
enqueue(10); enqueue(20); enqueue(30);
printf("Dequeued: %d\n", dequeue());
printf("Dequeued: %d\n", dequeue());
return 0;
}
int queue[SIZE];
int front = -1, rear = -1;
int peep() {
if (front == -1) {
printf("Queue is Empty\n");
return -1;
}
return queue[front];
}
int main() {
enqueue(10); enqueue(20); enqueue(30);
printf("Front Element: %d\n", peep());
return 0;
}
4. Display Elements of Circular Queue
#include <stdio.h>
#define SIZE 5
int queue[SIZE];
int front = -1, rear = -1;
void display() {
if (front == -1) {
printf("Queue is Empty\n");
return;
}
int i = front;
printf("Queue Elements: ");
while (i != rear) {
printf("%d ", queue[i]);
i = (i + 1) % SIZE;
}
printf("%d\n", queue[rear]); // Display rear element
}
int main() {
enqueue(10); enqueue(20); enqueue(30);
display();
return 0;
}
Review Questions
1. Which technique of searching an element in an array would you prefer to use and in
which situation?
2. Define sorting. What is the importance of sorting?
3. What are the different types of sorting techniques? ‘Which sorting technique has the
least worst case?
4. Explain the difference between bubble sort and quick sort. Which one is more
efficient?
5. Sort the elements 77, 49, 25, 12, 9, 33, 56, 81 using
(a) insertion sort (c) bubble sort (e) quick sort
(b) selection sort (d) merge sort
7. Quick sort shows quadratic behaviour in certain situations. Justify.
8. If the following sequence of numbers is to be sorted using quick sort, then show the
iterations of the sorting process.
42,34, 75,23, 21, 18,90, 67, 78
13. Write a recursive function to perform selection sort.
14. Compare the running time complexity of different sorting algorithms.
15. Discuss the advantages of insertion sort.
- ANSWER -
1. Linear Search:
○ Preferred when the array is unsorted or small.
○ Time Complexity: O(n) (worst case).
2. Binary Search:
○ Preferred for sorted arrays.
○ Time Complexity: O(log n) (worst case).
○ It repeatedly divides the array into two halves to locate the
element.
Importance of Sorting:
● Efficient Searching: Enables binary search for faster element
retrieval.
● Data Organization: Helps in organizing data systematically.
● Improves Algorithm Efficiency: Sorting simplifies complex
operations like merging datasets.
● Visualization and Presentation: Makes data more readable.
Least Worst Case: Merge Sort and Heap Sort have a worst-case time
complexity of O(n logn)
4. Explain the difference between bubble sort and quick sort. Which one is
more efficient?
Quick Sort is more efficient for large datasets due to its average-case time
complexity of O(n log n).
5. Sort the elements 77, 49, 25, 12, 9, 33, 56, 81 using:
8. Iterations of Quick Sort for 42, 34, 75, 23, 21, 18, 90, 67, 78
Programming Exercises
1. Write a program to implement bubble sort. Given the numbers 7, 1, 4, 12, 67, 33,
and 45. How many swaps will be performed to sort these numbers using the
bubble sort.
2. Write a program to implement a sort technique that works by repeatedly stepping
through the list to be sorted.
3. Write a program to implement a sort technique in which the sorted array is built
one entry at a time.
4. Write a program to implement an in-place comparison sort.
5. Write a program to implement a sort technique that works on the principle of
divide and conquer strategy.
6. Write a program to implement partition-exchange sort.
Ans
int main() {
int arr[] = {7, 1, 4, 12, 67, 33, 45};
int n = sizeof(arr) / sizeof(arr[0]);
bubbleSort(arr, n);
return 0;
}
Explanation: This program sorts the array using the bubble sort technique. It counts the
number of swaps performed during the sorting process.
Output:
Sorted array: 1 4 7 12 33 45 67
Total swaps: 10
int main() {
int arr[] = {7, 1, 4, 12, 67, 33, 45};
int n = sizeof(arr) / sizeof(arr[0]);
selectionSort(arr, n);
return 0;
}
Explanation: This program implements the selection sort algorithm, which
repeatedly selects the minimum element from the unsorted part of the list and swaps it
with the first unsorted element.
Output:
Sorted array: 1 4 7 12 33 45 67
Explanation: This program implements the insertion sort algorithm, which builds the
sorted array one entry at a time by inserting each element into its correct position.
Output:
Sorted array: 1 4 7 12 33 45 67
Output:
Sorted array: 1 4 7 12 33 45 67
int i = 0, j = 0, k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);
merge(arr, l, m, r);
}
}
int main() {
int arr[] = {7, 1, 4, 12, 67, 33, 45};
int n = sizeof(arr) / sizeof(arr[0]);
mergeSort(arr, 0, n - 1);
Output:
Sorted array: 1 4 7 12 33 45 67
int main() {
int arr[] = {7, 1, 4, 12, 67, 33, 45};
int n = sizeof(arr) / sizeof(arr[0]);
quickSort(arr, 0, n - 1);
Explanation: This program implements quick sort, which uses partition-exchange strategy,
where the array is divided into two subarrays and elements are placed around a pivot to sort the
array.
Output:
Sorted array: 1 4 7 12 33 45 67
Searching Algorithms
1. Write a program to search an element in an array using linear search.
2. Write a program to search an element in an array using binary search.
3. Write a program to search an element in an array using interpolation search.
Ans
1. Linear Search
Linear search scans each element of the array sequentially until it finds the target
element.
#include <stdio.h>
int main() {
int arr[] = {10, 20, 30, 40, 50};
int n = sizeof(arr) / sizeof(arr[0]);
int target = 30;
int result = linearSearch(arr, n, target);
if (result != -1) {
printf("Element found at index %d\n", result);
} else {
printf("Element not found\n");
}
return 0;
}
2. Binary Search
Binary search works on sorted arrays and divides the search range in half after each
comparison.
#include <stdio.h>
if (arr[mid] == target)
return mid; // Element found at index mid
else if (arr[mid] < target)
left = mid + 1; // Target is on the right half
else
right = mid - 1; // Target is on the left half
}
return -1; // Element not found
}
int main() {
int arr[] = {10, 20, 30, 40, 50};
int n = sizeof(arr) / sizeof(arr[0]);
int target = 30;
int result = binarySearch(arr, n, target);
if (result != -1) {
printf("Element found at index %d\n", result);
} else {
printf("Element not found\n");
}
return 0;
}
3. Interpolation Search
Interpolation search is an improvement over binary search for uniformly distributed data.
It tries to estimate the position of the target based on the value.
#include <stdio.h>
if (arr[pos] == target)
return pos; // Element found at index pos
else if (arr[pos] < target)
low = pos + 1; // Target is on the right side
else
high = pos - 1; // Target is on the left side
}
return -1; // Element not found
}
int main() {
int arr[] = {10, 20, 30, 40, 50};
int n = sizeof(arr) / sizeof(arr[0]);
int target = 30;
int result = interpolationSearch(arr, n, target);
if (result != -1) {
printf("Element found at index %d\n", result);
} else {
printf("Element not found\n");
}
return 0;
}
Sorting Algorithms
1. Write a program in C to sort an array using bubble sort algorithm.
2. Write a program in C to sort an array using insertion sort algorithm.
3. Write a program in C to sort an array using selection sort algorithm.
4. Write a program in C to sort an array using quick sort algorithm.
5. Write a program in C to sort an array using merge sort algorithm.
Answers
Bubble sort repeatedly swaps adjacent elements if they are in the wrong order. The
process continues until the array is sorted.
#include <stdio.h>
int main() {
int arr[] = {64, 25, 12, 22, 11};
int n = sizeof(arr) / sizeof(arr[0]);
bubbleSort(arr, n);
Insertion sort builds the final sorted array one item at a time by repeatedly picking the
next item and inserting it into the sorted part.
#include <stdio.h>
int main() {
int arr[] = {64, 25, 12, 22, 11};
int n = sizeof(arr) / sizeof(arr[0]);
insertionSort(arr, n);
Selection sort repeatedly selects the minimum element from the unsorted part of the
array and swaps it with the first unsorted element.
#include <stdio.h>
int main() {
int arr[] = {64, 25, 12, 22, 11};
int n = sizeof(arr) / sizeof(arr[0]);
selectionSort(arr, n);
printf("Sorted array: ");
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
return 0;
}
Quick sort is a divide-and-conquer algorithm that partitions the array into two subarrays,
sorts them independently, and then combines the results.
#include <stdio.h>
#include <stdlib.h>
int main() {
int arr[] = { 4, 2, 5, 3, 1 };
int n = sizeof(arr) / sizeof(arr[0]);
Merge sort is a divide-and-conquer algorithm that divides the array into two halves, sorts
them recursively, and then merges them.
#include <stdio.h>
void merge(int arr[], int left, int mid, int right) {
int n1 = mid - left + 1;
int n2 = right - mid;
int i = 0, j = 0, k = left;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
int main() {
int arr[] = {64, 25, 12, 22, 11};
int n = sizeof(arr) / sizeof(arr[0]);
mergeSort(arr, 0, n - 1);