All Questions
All Questions
● Mathematical Analysis:
○ Basic Operation: The basic operation is the comparison A[i] > max within the loop.
○ Number of Basic Operations: The loop runs from 1 to n-1, which means it iterates
n-1 times. Therefore, the comparison A[i] > max is executed n-1 times.
○ Time Complexity: The time complexity of this algorithm is determined by how
many times the basic operation is executed. Since it's n-1, the time complexity is
linear, or O(n). This means the time taken by the algorithm increases in direct
proportion to the size of the input array.
Question 3: Explain the general plan for analyzing the efficiency of a recursive algorithm.
Write the algorithm to find a factorial of a given number. Derive its efficiency.
● General Plan for Analyzing Recursive Algorithm Efficiency:
1. Decide on Input Size: Determine the parameter that indicates the size of the input
(e.g., 'n' for factorial, number of elements in a list).
2. Identify Basic Operation: Pinpoint the operation that is executed most frequently
within the recursion (e.g., the multiplication in factorial).
3. Set Up a Recurrence Relation: Create an equation (recurrence relation) that
expresses the number of times the basic operation is executed as a function of the
input size. This relation will have two parts:
■ Base Case: Defines the number of operations for the smallest input(s).
■ Recursive Case: Relates the number of operations for an input of size 'n' to
the number of operations for smaller inputs (e.g., 'n-1').
4. Solve the Recurrence Relation: Use mathematical techniques (like backward
substitution, master theorem, etc.) to find a closed-form solution for the recurrence
relation. This solution will give you the efficiency class (e.g., O(n), O(log n), O(n^2)).
● Algorithm for Factorial:
ALGORITHM Factorial(n)
//Input: A non-negative integer n
//Output: n! (the factorial of n)
if n = 0
return 1
else
return n * Factorial(n-1)
● Efficiency Derivation:
1. Input Size: The input size is n, the number for which we're calculating the factorial.
2. Basic Operation: The basic operation is the multiplication (n * Factorial(n-1)).
3. Recurrence Relation:
■ Let T(n) be the number of multiplications to compute n!.
■ Base case: T(0) = 0 (no multiplication needed when n=0)
■ Recursive case: T(n) = T(n-1) + 1 (one multiplication is done, plus the
multiplications needed for (n-1) !)
4. Solving the Recurrence:
■ We can expand the recurrence:
■ T(n) = T(n-1) + 1
■ T(n-1) = T(n-2) + 1
■ T(n-2) = T(n-3) + 1
■ ...
■ T(1) = T(0) + 1
■ Substituting back:
■ T(n) = (T(n-2) + 1) + 1 = T(n-2) + 2
■ T(n) = (T(n-3) + 1) + 2 = T(n-3) + 3
■ ...
■ T(n) = T(0) + n
■ Since T(0) = 0, we have T(n) = n.
5. Efficiency Class: The algorithm makes n multiplications. Therefore, the time
complexity is O(n), which is linear.
Question 4: Apply a quick sort algorithm to sort the list E, X, A, M, P, L, E in alphabetical
order. Draw the tree of recursive calls made.
● Quick Sort Algorithm: Quick sort is a divide-and-conquer algorithm. It works by selecting
a 'pivot' element from the array and partitioning the other elements into two sub-arrays,
according to whether they are less than or greater than the pivot. The sub-arrays are then
recursively sorted.
● Sorting the List E, X, A, M, P, L, E:
1. Initial List: E, X, A, M, P, L, E
2. Pivot Selection: Let's choose the first element, E, as the pivot.
3. Partitioning:
■ Elements less than E: A, E, E, L
■ Elements greater than E: X, M, P
4. Recursive Calls:
■ Left Sub-array (A, E, E, L):
■ Pivot: A
■ Less than A: [ ]
■ Greater than A: E, E, L
■ Recursive call on [ ] (base case, already sorted)
■ Recursive call on (E, E, L):
■ Pivot: E
■ Less than E: E, E
■ Greater than E: L
■ Recursive call on (E, E) (base case or further partitioning if
needed)
■ Recursive call on (L) (base case, already sorted)
■ Right Sub-array (X, M, P):
■ Pivot: X
■ Less than X: M, P
■ Greater than X: [ ]
■ Recursive call on (M, P):
■ Pivot: M
■ Less than M: [ ]
■ Greater than M: P
■ Recursive call on [ ] (base case)
■ Recursive call on (P) (base case)
■ Recursive call on [ ] (base case)
5. Concatenation: The sorted sub-arrays and the pivot are combined at each step.
● Tree of Recursive Calls:
E, X, A, M, P, L, E
/ \
A, E, E, L X, M, P
/ \ / \
A E, E, L M, P X
/ \ / \
E, E L M P
/ \
E E
● Sorted List: A, E, E, L, M, P, X
Question 5: List out the advantages and disadvantages of the divide and conquer
approach.
● Advantages:
○ Solves Difficult Problems: Divide and conquer can be very effective for solving
conceptually difficult problems.
○ Efficiency: Often leads to more efficient algorithms. For example, merge sort and
quicksort have better time complexities (O(n log n)) compared to some simpler
sorting algorithms (O(n^2)).
○ Parallelism: Divide and conquer algorithms are naturally suited for parallel
execution. Since the subproblems are independent, they can be solved
concurrently on multiple processors.
○ Cache Performance: Can improve cache performance by working on smaller
subproblems that fit more easily into cache memory.
● Disadvantages:
○ Recursion Overhead: Recursive implementations can have overhead due to
function calls, which can sometimes make them slower than iterative solutions for
small problem sizes.
○ Complexity: Divide and conquer algorithms can sometimes be more complex to
design and implement compared to simpler algorithms.
○ Space Complexity: Can sometimes have higher space complexity due to the
storage of intermediate subproblems (e.g., in merge sort).
○ Not Always Efficient: Not all problems benefit from a divide and conquer
approach. For some problems, simpler algorithms might be more efficient.
Question 6: Write the control abstraction for the divide and conquer technique.
● Control Abstraction:
DAndC(P)
{
if (small(P)) // Check if the problem size is small enough to
solve directly
return S(P); // Solve the small problem directly (base
case)
else {
divide P into smaller instances P1, P2, ..., Pk; //
Divide the problem into subproblems
for (i = 1 to k)
yi = DAndC(Pi); // Recursively solve each subproblem
return combine(y1, y2, ..., yk); // Combine the solutions
of the subproblems
}
}
● Explanation:
○ DAndC(P): Represents the divide and conquer algorithm for a problem instance P.
○ small(P): A boolean function that checks if the problem instance P is small enough
to be solved directly. This is the base case of the recursion.
○ S(P): A function that solves the small problem instance P directly.
○ divide P into smaller instances P1, P2, ..., Pk: Divides the problem P into k smaller
subproblems P1, P2, ..., Pk. The value of k can vary depending on the problem.
○ yi = DAndC(Pi): Recursively calls the divide and conquer algorithm on each of the
subproblems Pi to obtain their solutions yi.
○ combine(y1, y2, ..., yk): Combines the solutions y1, y2, ..., yk of the subproblems to
produce the solution to the original problem P.
Question 7: Give the general plan for analyzing time efficiency of Recursive algorithms
and also analyze the Tower of Hanoi Recursive algorithm.
● General Plan for Analyzing Time Efficiency of Recursive Algorithms: (This is the
same as in Question 3)
1. Decide on Input Size: Determine the parameter that indicates the size of the input.
2. Identify Basic Operation: Pinpoint the operation that is executed most frequently
within the recursion.
3. Set Up a Recurrence Relation: Create an equation (recurrence relation) that
expresses the number of times the basic operation is executed as a function of the
input size. This relation will have two parts:
■ Base Case: Defines the number of operations for the smallest input(s).
■ Recursive Case: Relates the number of operations for an input of size 'n' to
the number of operations for smaller inputs.
4. Solve the Recurrence Relation: Use mathematical techniques to find a
closed-form solution for the recurrence relation. This solution will give you the
efficiency class.
● Analysis of the Tower of Hanoi:
○ Algorithm:
ALGORITHM TowerOfHanoi(n, source, dest, aux)
//Input: n disks, source peg, destination peg, auxiliary peg
//Output: Moves to transfer n disks from source to dest
if n = 1
move disk from source to dest
else
TowerOfHanoi(n-1, source, aux, dest) // Move top n-1
disks from source to aux
move disk from source to dest // Move the
largest disk from source to dest
TowerOfHanoi(n-1, aux, dest, source) // Move n-1 disks
from aux to dest
○ Explanation:
1. Base Case: If n = 1, simply move the disk from the source to the destination
peg.
2. Recursive Steps:
■ Move the top n-1 disks from the source peg to the auxiliary peg, using
the destination peg as the auxiliary.
■ Move the nth (largest) disk from the source peg to the destination peg.
■ Move the n-1 disks from the auxiliary peg to the destination peg, using
the source peg as the auxiliary.
○ Efficiency Analysis:
1. Input Size: The input size is n, the number of disks.
2. Basic Operation: The basic operation is moving a disk from one peg to
another (move disk from source to dest).
3. Recurrence Relation:
■ Let T(n) be the number of moves to solve the Tower of Hanoi problem
with n disks.
■ Base case: T(1) = 1 (one move is needed to move 1 disk)
■ Recursive case: T(n) = 2T(n-1) + 1 (moves for n-1 disks to aux, one
move for the nth disk, and moves for n-1 disks to dest)
4. Solving the Recurrence:
■ T(n) = 2T(n-1) + 1
■ T(n-1) = 2T(n-2) + 1
■ T(n-2) = 2T(n-3) + 1
■ ...
■ T(2) = 2T(1) + 1
■ Substituting back:
■ T(n) = 2(2T(n-2) + 1) + 1 = 2^2T(n-2) + 2 + 1
■ T(n) = 2^2(2T(n-3) + 1) + 2 + 1 = 2^3T(n-3) + 2^2 + 2 + 1
■ ...
■ T(n) = 2^(n-1)T(1) + 2^(n-2) + 2^(n-3) + ... + 2 + 1
■ Since `