DAA All 5 Units Notes
DAA All 5 Units Notes
DAA All 5 Units Notes
UNIT 1: INTRODUCTION
Syllabus
1. Introduction: Algorithms, Analyzing Algorithms, Complexity of Algorithms, Growth
of Functions.
2. Performance Measurements.
• Shell Sort
• Quick Sort
• Merge Sort
• Heap Sort
1 Introduction to Algorithms
1.1 Definition of an Algorithm
An algorithm is a clear and precise sequence of instructions designed to solve a specific
problem or perform a computation. It provides a step-by-step method to achieve a de-
sired result. .
1
ITECH WORLD AKTU
2
ITECH WORLD AKTU
Example:
3
ITECH WORLD AKTU
2 Complexity of Algorithms
2.1 Time Complexity
Time Complexity is the computational complexity that describes the amount of time
it takes to run an algorithm as a function of the length of the input.
Cases of Time Complexity:
• Best Case: The minimum time required for the algorithm to complete, given the
most favorable input. Example: In Binary Search, the best-case time complexity is
O(1) when the target element is the middle element.
• Average Case: The expected time required for the algorithm to complete, av-
eraged over all possible inputs. Example: For Quick Sort, the average-case time
complexity is O(n log n).
• Worst Case: The maximum time required for the algorithm to complete, given the
least favorable input. Example: In Linear Search, the worst-case time complexity
is O(n) when the element is not present in the array.
Example:
• Total Space: The total space used by the algorithm, including both the input and
auxiliary space.
Example:
3 Growth of Functions
Growth of Functions describes how the time or space requirements of an algorithm
grow with the size of the input. The growth rate helps in understanding the efficiency of
an algorithm.
Examples:
4
ITECH WORLD AKTU
5
ITECH WORLD AKTU
3.5 Recurrences
Recurrence relations are equations that express a sequence in terms of its preceding
terms. In the context of Data Structures and Algorithms (DAA), a recurrence relation
often represents the time complexity of a recursive algorithm. For example, the time
complexity T (n) of a recursive function can be expressed as:
n
T (n) = a · T + f (n)
b
where:
• a is the number of subproblems in the recursion,
• b is the factor by which the subproblem size is reduced in each recursive call,
• f (n) represents the cost of the work done outside of the recursive calls.
There are several methods to solve recurrence relations:
1. Substitution Method: Guess the form of the solution and use mathematical
induction to prove it.
2. Recursion Tree Method: Visualize the recurrence as a tree where each node
represents the cost of a recursive call and its children represent the costs of the
subsequent subproblems.
6
ITECH WORLD AKTU
3. Master Theorem: Provides a direct way to find the time complexity of recurrences
n logb a
of the form T (n) = a · T b + f (n) by comparing f (n) to n .
1. Case 1: If f (n) = O(nlogb a−ϵ ) for some ϵ > 0, then T (n) = Θ(nlogb a ).
2. Case 2: If f (n) = Θ(nlogb a ·logk n) for some k ≥ 0, then T (n) = Θ(nlogb a ·logk+1 n).
3. Case 3: If f (n) = Ω(nlogb a+ϵ ) for some ϵ > 0 and if af nb ≤ cf (n) for some c < 1
Example:
• logb a = log2 2 = 1.
Question 1.6
Solve the recurrence relation:
n
T (n) = 7T + n2
2
Now, consider another algorithm with the recurrence:
n
T ′ (n) = aT ′ + n2
4
Find the largest integer a such that the algorithm T ′ runs faster than the first algorithm.
Solution:
n n
T (n) = 7T + n2 and T ′ (n) = aT ′ + n2
2 4
7
ITECH WORLD AKTU
By comparing, we have:
a = 7, b = 2, f (n) = n2
Thus,
T (n) = Θ(n2.81 )
Now for the second recurrence:
log 7 log a log 7
= ⇒ log a = × log 4 = 1.6902
log 2 log 4 log 2
Taking antilog, we get:
a = 48.015
Thus, for a = 49, algorithm A′ will have the same complexity as A. The largest
integer a such that A′ is faster than A is:
a = 48
Question 1.7
Solve the recurrence relation:
n
T (n) = 7T + n2
3
Now, consider another algorithm with the recurrence:
n
S(n) = aS + n2
9
Find the largest integer a such that the algorithm S runs faster than the first algorithm.
Solution:
n n
T (n) = 7T + n2 and S(n) = aS + n2
3 9
Comparing the equations:
a = 7, b = 3, f (n) = n2
8
ITECH WORLD AKTU
Question 1.8
Solve the recurrence relation:
√
T (n) = T ( n) + O(log n)
Solution:
Let:
m = log n and n = 2m ⇒ n1/2 = 2m/2
Then:
T (2m ) = T (2m/2 ) + O(log 2m ) Let x(m) = T (2m )
Substituting into the equation:
m
x(m) = x + O(m)
2
The solution is:
Recursion:
Recursion is a process where a function calls itself either directly or indirectly to solve
a problem. In recursion, a problem is divided into smaller instances of the same problem,
and solutions to these smaller instances are combined to solve the original problem.
Recursion typically involves two main parts:
• Base Case: A condition under which the recursion stops.
• Recursive Case: The part where the function calls itself to break the problem
into smaller instances.
Example of Recursion: Let’s take the example of calculating the factorial of a
number n, which is defined as:
n! = n × (n − 1) × (n − 2) × · · · × 1
9
ITECH WORLD AKTU
In this example, the base case is factorial(0) = 1, and the recursive case is n×factorial(n−
1).
Recursion Tree:
A recursion tree is a tree representation of the recursive calls made by a recursive
algorithm. Each node represents a function call, and its children represent the subsequent
recursive calls. The depth of the tree represents the depth of recursion.
shellSort(arr, n):
gap = n // 2 # Initialize the gap size
while gap > 0:
for i = gap to n-1:
temp = arr[i]
j = i
while j >= gap and arr[j - gap] > temp:
arr[j] = arr[j - gap]
j = j - gap
arr[j] = temp
gap = gap // 2
Example: Let’s sort the array [12, 34, 54, 2, 3] using Shell sort.
Step 1: Initial array
[12, 34, 54, 2, 3]
1. Start with gap = 5//2 = 2, meaning the array will be divided into sublists based
on the gap 2.
10
ITECH WORLD AKTU
• Compare elements at index 0 and 2: [12, 54]. No change since 12 < 54.
• Compare elements at index 1 and 3: [34, 2]. Swap since 34 > 2, resulting in:
• Compare elements at index 2 and 4: [54, 3]. Swap since 54 > 3, resulting in:
2. Reduce gap to 1: gap = 2//2 = 1. Now we perform insertion sort on the whole
array:
• Compare index 0 and 1: [12, 2]. Swap since 12 > 2, resulting in:
• Compare index 1 and 2: [12, 3]. Swap since 12 > 3, resulting in:
• Shell sort is more efficient than insertion sort for large lists, especially when elements
are far from their final positions.
• The efficiency depends on the choice of the gap sequence. A commonly used se-
quence is gap = n//2, reducing until gap equals 1.
1. Choose a Pivot: Select an element from the array to act as the pivot.
2. Partition: Rearrange the array such that elements less than the pivot come before
it, and elements greater come after it.
11
ITECH WORLD AKTU
3. Recursively Apply: Apply the same process to the sub-arrays formed by the
partition.
Pseudocode:
QuickSort(arr, low, high):
if low < high:
pivotIndex = Partition(arr, low, high)
QuickSort(arr, low, pivotIndex - 1)
QuickSort(arr, pivotIndex + 1, high)
[10, 7, 8, 9, 1, 5]
• Choose pivot: 5
[1, 5, 7, 8, 9, 10]
Visualization:
Initial Array:
[10, 7, 8, 9, 1, 5]
After Partitioning:
[1, 5, 8, 9, 7, 10]
12
ITECH WORLD AKTU
1. Divide: Recursively divide the array into two halves until each sub-array contains
a single element.
2. Merge: Merge the sorted sub-arrays to produce sorted arrays until the entire array
is merged.
Pseudocode:
13
ITECH WORLD AKTU
arr[k] = R[j]
j = j + 1
k = k + 1
and
[9, 10, 82]
Visualization:
Initial Array:
[38, 27, 43, 3, 9, 82, 10]
• Stable Sort: Merge Sort maintains the relative order of equal elements.
• Slower for Small Lists: It may be slower compared to algorithms like Quick Sort
for smaller lists.
14
ITECH WORLD AKTU
1. Build a Max Heap: Convert the input array into a max heap where the largest
element is at the root.
2. Extract Max: Swap the root of the heap (maximum element) with the last element
of the heap and then reduce the heap size by one. Heapify the root to maintain the
max heap property.
3. Repeat: Continue the extraction and heapify process until the heap is empty.
Pseudocode:
HeapSort(arr):
n = length(arr)
BuildMaxHeap(arr)
for i = n - 1 down to 1:
swap arr[0] with arr[i]
Heapify(arr, 0, i)
BuildMaxHeap(arr):
n = length(arr)
for i = n // 2 - 1 down to 0:
Heapify(arr, i, n)
Heapify(arr, i, n):
largest = i
left = 2 * i + 1
right = 2 * i + 2
if left < n and arr[left] > arr[largest]:
largest = left
if right < n and arr[right] > arr[largest]:
largest = right
if largest != i:
swap arr[i] with arr[largest]
Heapify(arr, largest, n)
• In-Place Sorting: Heap Sort does not require additional space beyond the input
array.
• Time Complexity: It has a time complexity of O(n log n) for both average and
worst cases.
15
ITECH WORLD AKTU
• Not Stable: Heap Sort is not a stable sort, meaning equal elements may not retain
their original order.
• Performance: It can be slower compared to algorithms like Quick Sort due to the
overhead of heap operations.
2. Distribute Elements: Place each element into the appropriate bucket based on
its value.
3. Sort Buckets: Sort each bucket individually using another sorting algorithm (e.g.,
Insertion Sort).
4. Concatenate Buckets: Combine the sorted buckets into a single sorted array.
Pseudocode:
BucketSort(arr):
minValue = min(arr)
maxValue = max(arr)
bucketCount = number of buckets
buckets = [[] for _ in range(bucketCount)]
16
ITECH WORLD AKTU
InsertionSort(arr):
for i from 1 to length(arr):
key = arr[i]
j = i - 1
while j >= 0 and arr[j] > key:
arr[j + 1] = arr[j]
j = j - 1
arr[j + 1] = key
• Insertion Sort: Maintain the order of elements with equal keys by inserting each
element into its correct position relative to previously sorted elements.
Pseudocode:
InsertionSort(arr):
for i from 1 to length(arr):
key = arr[i]
j = i - 1
while j >= 0 and arr[j] > key:
arr[j + 1] = arr[j]
j = j - 1
arr[j + 1] = key
17
ITECH WORLD AKTU
2. Sort by Digit: Sort the array by each digit using a stable sort (e.g., Counting
Sort).
CountingSort(arr, exp):
n = length(arr)
output = [0] * n
count = [0] * 10
for i in range(n):
index = (arr[i] // exp) % 10
count[index] += 1
for i in range(1, 10):
count[i] += count[i - 1]
for i in range(n - 1, -1, -1):
index = (arr[i] // exp) % 10
output[count[index] - 1] = arr[i]
count[index] -= 1
for i in range(n):
arr[i] = output[i]
Example: Consider the array:
18
ITECH WORLD AKTU
Question: Among Merge Sort, Insertion Sort, and Quick Sort, which algorithm
performs the best in the worst case? Apply the best algorithm to sort the list
E, X, A, M, P, L, E
in alphabetical order.
Answer: - Merge Sort has a worst-case time complexity of O(n log n). - Insertion
Sort has a worst-case time complexity of O(n2 ). - Quick Sort has a worst-case time
complexity of O(n2 ), though its average-case complexity is O(n log n).
In the worst case, Merge Sort performs the best among these algorithms.
Sorted List using Merge Sort:
Step-by-Step Solution:
1. Initial List:
• Given List:
E, X, A, M, P, L, E
E, X, A and M, P, L, E
3. Recursive Division:
19
ITECH WORLD AKTU
• Merge E and X, A:
– Merge X and A to get:
A, X
– Merge E and A, X to get:
A, E, X
• Merge M and P to get:
M, P
• Merge L and E to get:
E, L
• Merge M, P and E, L:
– Merge M and E, L, P to get:
E, L, M, P
• Merge A, E, X and E, L, M, P:
– Final merge results in:
A, E, E, L, M, P, X
6. Sorted List:
• Sorted List:
A, E, E, L, M, P, X
20
ITECH WORLD AKTU
21
ITECH WORLD AKTU
Subject Name: Design and Analysis of Algorithm
(BCS503)
Syllabus
• Red-Black Trees
• B-Trees
• Binomial Heaps
• Fibonacci Heaps
• Tries
• Skip List
• LEFT: A pointer to the left child node, which contains only nodes with keys less
than the current node’s key.
• KEY: The value stored in the current node. This value determines the order within
the tree.
• PARENT: A pointer to the parent node. The root node’s parent pointer is NULL.
• RIGHT: A pointer to the right child node, which contains only nodes with keys
greater than the current node’s key.
• The left subtree of a node contains only nodes with keys less than the node’s key.
• The right subtree of a node contains only nodes with keys greater than the node’s
key.
• Both the left and right subtrees must also be binary search trees.
1
Limitations of Binary Search Tree (BST)
Binary Search Trees (BSTs) have several limitations related to their complexity:
2
• Worst-Case Time Complexity: In the worst case, such as when the tree becomes
unbalanced (e.g., inserting sorted data), the height of the BST can reach O(n),
resulting in search, insertion, and deletion operations having a time complexity of
O(n).
• Space Complexity: Each node requires extra memory for storing pointers to
its children, which can lead to higher space complexity compared to array-based
structures, especially in unbalanced trees.
• Poor Performance with Sorted Data: If input data is already sorted, the BST
will degenerate into a linked list, causing all operations to degrade to O(n) time
complexity.
• Balancing Overhead: Self-balancing BSTs (like AVL or Red-Black Trees) re-
quire additional operations (rotations and recoloring), which add extra overhead to
insertion and deletion operations.
• Cache Inefficiency: Due to pointer-based navigation, BSTs exhibit poor cache
locality, leading to slower performance compared to structures like arrays.
Red-Black Trees
A Red-Black Tree is a type of self-balancing binary search tree in which each node contains
an extra bit for denoting the color of the node, either red or black. The tree maintains
its balance by following a set of rules during insertion and deletion operations.
3
Finding the Height of a Red-Black Tree Using Black
Height
In a Red-Black Tree, the black height of a node is defined as the number of black nodes
on the path from that node to any leaf, not including the node itself. The black height
is an important property that helps in maintaining the balance of the tree.
• The black height of a Red-Black Tree is the black height of its root node.
4
Calculating Black Height:
1. Start at the root node.
4. The value of bh when a leaf (NIL node) is reached is the black height of the tree.
• Thus, if the black height of a Red-Black Tree is bh, the maximum height of the tree
is 2 × bh.
Time Complexity:
Calculating the black height of a Red-Black Tree requires traversing from the root to any
leaf, resulting in a time complexity of O(log n), where n is the number of nodes in the
tree.
5
18. z.color = RED
19. INSERT-FIXUP(T, z)
6
Cases of RB Tree Insertion
• Case 1: Uncle is RED.
• Provides better worst-case time complexity for insertion, deletion, and search op-
erations.
7
if w.color == RED
w.color = BLACK
x.p.color = RED
LEFT-ROTATE(T, x.p)
w = x.p.right
if w.left.color == BLACK and w.right.color == BLACK
w.color = RED
x = x.p
else if w.right.color == BLACK
w.left.color = BLACK
w.color = RED
RIGHT-ROTATE(T, w)
w = x.p.right
w.color = x.p.color
x.p.color = BLACK
w.right.color = BLACK
LEFT-ROTATE(T, x.p)
x = T.root
else
(mirror image of the above)
x.color = BLACK
• Case 3: Sibling is BLACK, sibling’s left child is RED, and sibling’s right child is
BLACK.
8
B-Trees
A B-Tree is a self-balancing search tree in which nodes can have more than two children.
It is commonly used in databases and file systems to maintain sorted data and allow
searches, sequential access, insertions, and deletions in logarithmic time.
Properties of B-Trees:
• All leaves are at the same level.
9
Splitting a Child in B-Tree: B-Tree-Split-Child(x, i, y)
B-Tree-Split-Child(x, i, y)
1. z = Allocate-Node()
2. leaf[z] = leaf[y]
3. n[z] = t - 1
4. for j = 1 to t - 1
5. keyj[z] = key(j + t)[y]
6. if not leaf[y]
7. for j = 1 to t
8. cj[z] = c(j + t)[y]
9. n[y] = t - 1
10. for j = n[x] + 1 downto i + 1
11. c(j + 1)[x] = cj[x]
12. c(i + 1)[x] = z
13. for j = n[x] downto i
14. key(j + 1)[x] = keyj[x]
15. keyi[x] = keyt[y]
16. n[x] = n[x] + 1
10
4. Recursively delete the key from the appropriate node.
Characteristics of B-Trees:
• B-Trees are height-balanced.
• Insertion and deletion are done in such a way that the tree remains balanced.
Binomial Heaps
Binomial Heaps are a type of heap data structure that supports efficient merging of two
heaps. It is composed of a collection of binomial trees that satisfy the heap property.
11
Properties of Binomial Heaps:
• Each binomial heap is a collection of binomial trees.
• The root has the smallest key and the heap is represented as a linked list of binomial
trees.
1. Both heaps are merged into one by merging their respective binomial trees.
3. If two trees of the same degree appear, they are merged into one tree by linking.
12
3. Initialize pointers: x, prev x, and next x
4. x ← head of H
5. While next x ̸= NULL:
6. If Degree(x) ̸= Degree(next x) or Degree(next x) == Degree(next next x)
7. Move to the next tree
8. Else if Key(x) ≤ Key(next x)
9. Link next x as a child of x
10. next x ← next next x
11. Else
12. Link x as a child of next x
13. x ← next x
14. Return H
2. Both trees have the same degree: The two trees are merged.
3. Three trees of the same degree appear consecutively: The middle tree is merged
with one of its neighbors.
4. Two consecutive trees have the same degree: The tree with the smaller root is made
the parent.
BINOMIAL-HEAP-EXTRACT-MIN(H)
1. Find the root x with the minimum key in the root list of H
2. Remove x from the root list of H
3. Create a new binomial heap H ′
13
4. Make the children of x a separate binomial heap by reversing the order of the linked
list of x’s children
5. Union H and H ′
6. Return x
4 BINOMIAL-HEAP-DECREASE-KEY Algorithm
The decrease-key operation reduces the key of a given node to a smaller value and then
adjusts the heap to maintain the binomial heap property.
BINOMIAL-HEAP-DECREASE-KEY(H, x, k)
1. If k > x.key then Error: New key is larger than current key
2. Set x.key ← k
3. Set y ← x, z ← y.p
4. While z ̸= NIL and y.key < z.key:
5. Exchange y and z
6. Set y ← z, z ← y.p
14
4.1 Time Complexity
The time complexity for BINOMIAL-HEAP-DECREASE-KEY is O(log n).
15
9. Set x ← A[d]
10. Set A[d] ← temp
11. Link A[d] as a child of x
12. Else
13. Link x as a child of A[d]
14. End if
15. Increment d by 1
16. End while
17. Set H.min to the minimum of the roots of H
16
5.7 Algorithm for Minimum
FIB-HEAP-MINIMUM(H)
1. Return H.min
17
6 Trie and Skip List
6.1 Trie and Its Properties
Trie: A trie, also known as a prefix tree or digital tree, is a tree data structure used to
store a dynamic set of strings, where the keys are usually strings. It provides a way to
efficiently search, insert, and delete keys.
Properties:
• Each node has a boolean flag indicating whether it marks the end of a key.
• The time complexity of search, insert, and delete operations is proportional to the
length of the key.
18
6.3 Skip List and Its Properties
Skip List: A skip list is a data structure that allows fast search within an ordered
sequence of elements. It uses multiple layers of linked lists to skip over elements, making
search operations faster.
Properties:
• Skip lists have multiple levels of linked lists.
• Each element in a higher level list represents a shortcut to the lower level lists.
• The time complexity of search, insertion, and deletion operations is O(log n) on
average.
• The space complexity is O(n log n).
19
6.5 Divide and Conquer Approach to Compute xn
POWER(x, n)
1. If n = 0 then Return 1
2. If n is even:
3. Set y ← POWER(x, n/2)
4. Return y × y
5. Else
6. Return x× POWER(x, n − 1)
20
ITECH WORLD AKTU
Design and Analysis of Algorithms (BCS503)
TU
UNIT 3: Divide and Conquer & Greedy Methods
AK
Syllabus
• Divide and Conquer with examples such as Sorting, Matrix Multiplication, Convex Hull,
and Searching.
• Greedy Methods with examples such as Optimal Reliability Allocation, Knapsack, Min-
imum Spanning Trees (Prim’s and Kruskal’s algorithms), Single Source Shortest Paths
(Dijkstra’s and Bellman-Ford algorithms).
D
RL
Divide and Conquer
The Divide and Conquer technique involves solving problems by breaking them into smaller
sub-problems, solving each sub-problem independently, and then combining their results. It
O
parts.
• Conquer: The sub-problems are solved recursively. If the sub-problem is small enough,
solve it directly.
• Combine: The solutions of the sub-problems are combined to get the final solution to
H
1
ITECH WORLD AKTUDesign and Analysis of Algorithms (BCS503)
TU
• Merge the two sorted halves to get the sorted array.
Example: For an array [38, 27, 43, 3, 9, 82, 10], the array is divided and merged in steps.
Matrix Multiplication
AK
Matrix multiplication is a fundamental operation in many areas of computer science and math-
ematics. There are two main methods for matrix multiplication:
D
The conventional method of multiplying two matrices A and B follows the standard O(n3 )
approach. If A and B are n × n matrices, the product matrix C = AB is calculated as:
RL
n
X
C[i][j] = A[i][k] · B[k][j]
k=1
The time complexity of this method is O(n3 ) since each element of the resulting matrix C
O
In the divide and conquer approach, matrices A and B are divided into smaller sub-matrices.
This method recursively multiplies the sub-matrices and combines the results to obtain the final
product matrix. The key idea is to reduce the matrix multiplication problem size by breaking
down large matrices into smaller parts.
H
Strassen’s Algorithm is an optimized version of the divide and conquer method. It reduces the
time complexity of matrix multiplication from O(n3 ) to approximately O(n2.81 ).
Key Idea: Strassen’s method reduces the number of recursive multiplications by clev-
erly reorganizing matrix products. Instead of 8 recursive multiplications (as in the naive
IT
2
ITECH WORLD AKTUDesign and Analysis of Algorithms (BCS503)
n
1. Divide: - Split each n × n matrix A and B into four sub-matrices of size 2
× n2 . Let:
A11 A12 B11 B12
A= , B=
A21 A22 B21 B22
TU
M2 = (A21 + A22 )B11
M3 = A11 (B12 − B22 )
M4 = A22 (B21 − B11 )
M5 = (A11 + A12 )B22
AK
M6 = (A21 − A11 )(B11 + B12 )
M7 = (A12 − A22 )(B21 + B22 )
3. Combine: - Combine the seven products to get the final sub-matrices of C:
C11 = M1 + M4 − M5 + M7
C12 = M3 + M5
D
RL
C21 = M2 + M4
C22 = M1 − M2 + M3 + M6
Thus, the matrix C is:
C11 C12
O
C=
C21 C22
Recurrence Relation: The time complexity of Strassen’s Algorithm can be expressed by
W
Advantages: - Reduced time complexity compared to the conventional method, especially for
large matrices.
Disadvantages: - The algorithm involves more additions and subtractions, which increases
constant factors. - Implementation is more complex, and the recursive approach can lead to
IT
3
ITECH WORLD AKTUDesign and Analysis of Algorithms (BCS503)
Example:
Let’s multiply two 2 × 2 matrices using Strassen’s method.
Let A and B be:
1 2 5 6
A= , B=
3 4 7 8
Using Strassen’s method, we compute the seven products M1 , M2 , . . . , M7 and then combine
them to get the resulting matrix C.
The resulting product matrix C = AB is:
TU
19 22
C=
43 50
This example demonstrates the power of Strassen’s method in reducing the number of
AK
multiplications and solving matrix multiplication more efficiently.
2. Sort the remaining points based on the polar angle they make with P0 . If two points have
the same polar angle, keep the one that is closer to P0 .
H
3. Initialize the convex hull with the first three points from the sorted list.
(a) While the angle formed by the last two points in the hull and the current point
makes a non-left turn (i.e., the turn is clockwise or collinear), remove the second-to-
last point from the hull.
IT
5. After processing all points, the points remaining in the hull list form the convex hull.
4
ITECH WORLD AKTUDesign and Analysis of Algorithms (BCS503)
Initialize the convex hull with the first three points from the sorted list. each remaining point
pi the turn formed by the last two points of the hull and pi is not left
Remove the second-to-last point from the hull.
Add pi to the hull.
Return the points in the hull.
Time Complexity:
TU
• Sorting the points based on the polar angle takes O(n log n).
• Processing each point and constructing the convex hull takes O(n).
Thus, the overall time complexity of the Graham Scan algorithm is:
AK
O(n log n)
D
Binary Search is used to find an element in a sorted array. The array is divided into two halves,
and the search is performed in the half where the element may exist.
Algorithm:
RL
• Compare the middle element with the target value.
• If the target is smaller, search in the left half; otherwise, search in the right half.
O
article amsmath
W
Greedy Methods
The Greedy method constructs a solution step by step by selecting the best possible option
H
at each stage, without revisiting or considering the consequences of previous choices. It works
under the assumption that by choosing a local optimum at every step, the overall solution will
be globally optimal.
EC
4. Efficiency: Greedy algorithms are typically more efficient in terms of time complexity
because they solve sub-problems once and only make one pass over the input data.
5
ITECH WORLD AKTUDesign and Analysis of Algorithms (BCS503)
TU
AK
D
RL
0.2.1 Greedy Algorithm for Activity Selection
The Greedy Activity Selector algorithm selects activities based on their finish times. The idea
O
is to always choose the next activity that finishes first and is compatible with the previously
selected activities.
W
k = 1
for m = 2 to n:
EC
return A
6
ITECH WORLD AKTUDesign and Analysis of Algorithms (BCS503)
• (3, 5)
• (0, 6)
• (1, 4)
• (6, 10)
• (5, 7)
• (3, 8)
• (5, 9)
TU
• (8, 11)
AK
First, we sort the activities based on their finish times:
9 (0, 6)
10 (1, 4)
11 (3, 8)
Now we will select activities using the greedy approach: - Start with Activity 1 (2, 3) - The
next compatible activity is Activity 2 (3, 5) - Continue this process.
EC
• Activity 1: (2, 3)
• Activity 2: (3, 5)
IT
• Activity 3: (5, 7)
7
ITECH WORLD AKTUDesign and Analysis of Algorithms (BCS503)
RecursiveActivitySelector(S, F, k, n):
if k >= n:
return []
m = k + 1
while m <= n and S[m] < F[k]:
TU
m = m + 1
return [m] + RecursiveActivitySelector(S, F, m, n)
Iterative Approach:
IterativeActivitySelector(S, F):
AK
n = length(S)
A = {1} // The first activity is always selected
k = 1
for m = 2 to n:
if S[m] >= F[k]:
A = A {m}
k = m
D
RL
return A
An optimization problem is a problem in which we seek to find the best solution from a set of
feasible solutions. It involves maximizing or minimizing a particular objective function subject
to constraints.
W
• Making the locally optimal choice at each step, hoping it leads to a globally optimal
EC
solution.
• Ensuring that the greedy choice property and optimal substructure hold for the specific
problem.
IT
Common examples of optimization problems solved using greedy algorithms include the
Knapsack Problem, Minimum Spanning Tree, and Huffman Coding.
8
ITECH WORLD AKTUDesign and Analysis of Algorithms (BCS503)
Greedy Approach
The greedy approach for the Knapsack Problem follows these steps:
• Sort items by their value-to-weight ratio.
• Pick items with the highest ratio until the weight limit is reached.
TU
The Branch and Bound method is another approach to solve the Knapsack Problem efficiently
by exploring the solution space using an implicit tree structure:
• Implicit Tree: Each node represents a state of including or excluding an item.
• Upper Bound of Node: Calculate the maximum possible value that can be obtained
AK
from the current node to prune the tree.
• N =8
• P = {11, 21, 31, 33, 43, 53, 55, 65}
EC
Solution
To solve the problem using the greedy method, we calculate the value-to-weight ratio for each
item, sort them, and fill the knapsack until we reach the maximum weight M .
The total value obtained is 152.6.
Items in Knapsack
The items included in the knapsack are I1 , I2 , I3 , I4 , I5 , and a fraction of I6 .
Final Answer: Maximum value = 152.6.
9
ITECH WORLD AKTUDesign and Analysis of Algorithms (BCS503)
TU
0/1 Knapsack Problem using Dynamic Programming
Solve the following 0/1 knapsack problem using dynamic programming:
• P = {11, 21, 31, 33}
AK
• W = {2, 11, 22, 15}
• C = 40
• N =4
Solution
D
RL
We will solve this problem using the dynamic programming approach by creating a table to
keep track of the maximum value at each capacity.
Item Weight (W) Value (P) Capacity (C) Current Value Set
0 0 0 0 0 {(0,0)}
O
1 2 11 2 11 {(11,2)}
2 11 21 11 21 {(21,11)}
3 22 31 22 31 {(31,22)}
W
4 15 33 15 33 {(33,15)}
Starting with the initial set S0 = {(0, 0)}, we add items according to their weight and value,
H
Conclusion
IT
The greedy method provides an efficient way to solve the fractional knapsack problem, but it
may not yield an optimal solution for the 0/1 knapsack problem. For 0/1 knapsack, dynamic
programming or branch and bound methods are preferred.
10
ITECH WORLD AKTUDesign and Analysis of Algorithms (BCS503)
TU
Table 3: Comparison of Kruskal’s and Prim’s Algorithms
AK
• While there are vertices not in the MST:
– Select the edge with the minimum weight that connects a vertex in the MST to a
vertex outside it.
– Add the selected edge and vertex to the MST.
The minimum spanning tree consists of edges (A, B), (B, C), and (C, D) with total weight
6.
W
Kruskal’s Algorithm
Algorithm:
11
ITECH WORLD AKTUDesign and Analysis of Algorithms (BCS503)
TU
Prim’s Minimum Spanning Tree Algorithm in Detail
- Initialization: Start with any vertex. - Growth: Always pick the least weight edge that
expands the tree until all vertices are included. - Termination: When all vertices are included
AK
in the MST.
• Initialize distances from the source vertex to all others as infinity, except the source itself
(0).
D
• Create a priority queue and insert the source vertex.
RL
• While the queue is not empty:
– For each neighbor, calculate the potential distance through the current vertex.
– If the calculated distance is smaller, update it and add the neighbor to the queue.
W
H
EC
IT
12
ITECH WORLD AKTUDesign and Analysis of Algorithms (BCS503)
TU
AK
D
RL
O
W
H
Step 1: Initialization
EC
D ∞ -
E ∞ -
F ∞ -
G ∞ -
H ∞ -
13
ITECH WORLD AKTUDesign and Analysis of Algorithms (BCS503)
TU
E 7 C
F ∞ -
G ∞ -
H ∞ -
AK
Table 5: Distance Table After Extracting C
Node
D
Distance from A Previous Node
RL
A 0 -
B 3 A
C 2 A
D 7 C
E 7 C
O
F 9 B
G ∞ -
H ∞ -
W
C 2 A
D 7 C
E 7 C
F 9 B
G 10 D
H ∞ -
14
ITECH WORLD AKTUDesign and Analysis of Algorithms (BCS503)
TU
Table 8: Final Distance Table
Repeat the process of extracting the minimum node and updating the distances until all
nodes have been visited. After completing the process, the shortest path from A to H will be
AK
found.
Final Distance Table:
Conclusion: The shortest path from A to H is:
A→C→D→G→H
Bellman-Ford Algorithm D
RL
Algorithm:
• Initialize the distance of the source to 0 and all others to infinity.
• Check for negative weight cycles by iterating through all edges again.
Example: Consider a graph with vertices A, B, C and edges: - (A, B, 1) - (B, C, −2) -
(C, A, −1)
H
15
ITECH WORLD AKTUDesign and Analysis of Algorithms (BCS503)
However, it will fail to find a shortest path if the graph contains a negative weight cycle that
is reachable from the source node.
TU
process (updating distances), the algorithm performs one more iteration to check if any further
relaxation is possible. If a distance is updated in this extra iteration, a negative weight cycle
exists in the graph.
AK
The graph provided can be analyzed using the Bellman-Ford algorithm. The algorithm itera-
tively updates the shortest distances from the source node to all other nodes. Here’s how to
apply the Bellman-Ford algorithm:
D
RL
O
W
H
The graph contains both positive and negative weights. We will perform multiple relax-
ations, updating the shortest path estimates.
IT
16
ITECH WORLD AKTUDesign and Analysis of Algorithms (BCS503)
TU
4 0 2 4 7 -2
Table 9: Distance Table for Bellman-Ford Algorithm
The algorithm terminates after the last iteration when no more updates occur.
AK
D
RL
O
W
H
EC
IT
17
ITECH WORLD AKTUDesign and Analysis of Algorithms (BCS503)
class Graph:
def __init__(self, vertices):
self.V = vertices
TU
self.graph = []
AK
def bellman_ford(self, src):
dist = [float("Inf")] * self.V
dist[src] = 0
D
if dist[u] != float("Inf") and dist[u] + w < dist[v]:
dist[v] = dist[u] + w
RL
for u, v, w in self.graph:
if dist[u] != float("Inf") and dist[u] + w < dist[v]:
print("Graph contains negative weight cycle")
return
O
print("{0}\t\t{1}".format(i, dist[i]))
g = Graph(5)
g.add_edge(0, 1, 6)
H
g.add_edge(0, 2, 7)
g.add_edge(1, 2, 8)
g.add_edge(1, 3, 5)
EC
g.add_edge(1, 4, -4)
g.add_edge(2, 3, -3)
g.add_edge(2, 4, 9)
g.add_edge(3, 1, -2)
IT
g.add_edge(4, 0, 2)
g.add_edge(4, 3, 7)
g.bellman_ford(0)
18
ITECH WORLD AKTU
UNIT 4:
Syllabus
• Dynamic Programming with Examples Such as Knapsack.
Dynamic Programming
Dynamic Programming (DP) is a technique for solving complex problems by breaking
them down into simpler overlapping subproblems. It applies to problems exhibiting two
main properties:
1
ITECH WORLD AKTU
2. Other approaches like divide and conquer might solve the same subproblem multiple
times.
Example
The Fibonacci sequence is a classic example, where each number is the sum of the two
preceding ones. DP avoids redundant calculations by storing already computed values.
• Top-down: Starting with the main problem, then breaking it into subproblems
recursively (usually with memoization).
1. The solution to a problem can be constructed from the solutions to its subproblems.
2. Example: The shortest path in a graph can be obtained by combining the shortest
paths from intermediate nodes.
Overlapping Subproblems:
Memoization:
2
ITECH WORLD AKTU
Time Complexity: O(mn), where m and n are the lengths of the two strings.
namic 0/1-Knapsack(v, w, n, W)
3
ITECH WORLD AKTU
4
ITECH WORLD AKTU
Table 2: Comparison between Divide and Conquer, Dynamic Programming, and Greedy
Approach
Knapsack Problem
The Knapsack Problem is a classic example of dynamic programming, where the goal is
to maximize the value that can be put into a knapsack of limited capacity.
Problem Statement: Given weights and values of n items, put these items in a
knapsack of capacity W to get the maximum total value.
Formula:
where K(i, w) is the maximum value that can be obtained with i items and capacity w,
vi is the value of the ith item, and wi is the weight.
Example: Consider n = 3 items with the following values and weights:
Item Value Weight
1 60 10
2 100 20
3 120 30
5
ITECH WORLD AKTU
Knapsack capacity W = 50. The solution using dynamic programming will give us a
maximum value of 220.
Warshall’s Algorithm
Warshall’s algorithm is used to compute the transitive closure of a directed graph. The
transitive closure tells us whether there is a path between any two vertices in a graph.
Steps of Warshall’s Algorithm: 1. Initialize the transitive closure matrix using
the adjacency matrix of the graph. 2. For each intermediate vertex k, update the matrix
to indicate whether a path exists between two vertices i and j via k. 3. If there is a
direct edge from i to j, or a path through k, update the matrix entry to reflect the path.
4. Repeat this process for all vertices as intermediates to compute the final transitive
closure.
Algorithm:
T (i, j) = T (i, j) ∨ (T (i, k) ∧ T (k, j))
Where: - T (i, j) represents the transitive closure matrix entry for vertices i and j. - ∧
represents the logical AND operator, and ∨ represents the logical OR operator.
Example: Consider a graph with the following adjacency matrix:
0 1 0 1
0 0 1 0
0 0 0 1
0 0 0 0
After applying Warshall’s algorithm, the transitive closure will indicate all reachable
vertices, showing which nodes are reachable from each other.
Floyd-Warshall Algorithm
The Floyd-Warshall algorithm is used to find the shortest paths between every pair of
vertices in a weighted graph. Unlike Warshall’s algorithm, which focuses on transitive
closure, Floyd-Warshall computes the minimum distances between all pairs of vertices,
even if there are negative weights (but no negative cycles).
Steps of Floyd-Warshall Algorithm: 1. Initialize a distance matrix using the edge
weights of the graph. 2. For each intermediate vertex k, update the distance between
each pair of vertices i and j. 3. If the path through k offers a shorter route, update the
distance matrix entry to reflect the shorter path. 4. Repeat this process for all vertices
as intermediates to compute the shortest paths between all pairs.
Algorithm:
dij = min(dij , dik + dkj )
6
ITECH WORLD AKTU
Where: - dij represents the shortest distance from vertex i to vertex j. - dik and dkj
represent the distances from i to k and k to j, respectively. - The algorithm considers
all pairs of vertices and finds the shortest path for each pair using every vertex as an
intermediate node.
4. Output the distance matrix D, which now contains the shortest path between all
pairs.
7
ITECH WORLD AKTU
0 3 6 ∞ ∞
∞ 0 3 1 4
D0 =
∞ ∞ 0 1 ∞
∞ ∞ ∞ 0 2
∞ ∞ ∞ ∞ 0
8
ITECH WORLD AKTU
Final Result
The final distance matrix represents the shortest paths between all pairs of vertices.
0 3 6 4 6
∞ 0 3 1 3
∞ ∞ 0 1 ∞
∞ ∞ ∞ 0 2
∞ ∞ ∞ ∞ 0
Point Comparison
1 Warshall’s algorithm is used for computing the transi-
tive closure of a graph, whereas Floyd-Warshall is used
for computing the shortest paths between all pairs of
vertices.
2 Warshall’s algorithm only determines if a path exists,
while Floyd-Warshall finds the actual shortest path.
3 Floyd-Warshall works with weighted graphs, while War-
shall’s algorithm works on unweighted graphs.
4 Both algorithms use a dynamic programming approach,
updating the solution incrementally.
5 Both have a time complexity of O(n3 ), where n is the
number of vertices.
6 Warshall’s algorithm uses logical operators, whereas
Floyd-Warshall uses arithmetic operations.
Backtracking
Backtracking is a general algorithmic technique that incrementally builds candidates to
the solutions of a problem and abandons each partial candidate (backtracks) as soon as
it determines that the candidate cannot possibly be a valid solution.
9
ITECH WORLD AKTU
It is often used in problems involving combinatorial search, where the goal is to find
all or some solutions, and discarding non-promising paths as early as possible leads to
efficient exploration.
2. Check if this candidate leads to a solution. If not, discard the candidate and
backtrack to the previous step.
4. Repeat the process until all candidates are checked or the solution is found.
5. Backtrack whenever a candidate doesn’t work, and try the next possible solution.
6. Continue until the solution is complete or all possible options are exhausted.
3. Compute a bound on the minimum possible route length (using heuristics or lower-
bound calculation).
4. Eliminate any routes where the bound exceeds the known minimum distance.
6. If a route completes with a lower total distance than the known minimum, update
the minimum.
7. Repeat until all cities are explored or the minimum route is found.
10
ITECH WORLD AKTU
Graph Colouring
Graph colouring is the process of assigning colours to the vertices of a graph such that
no two adjacent vertices share the same colour. This problem is a type of combinatorial
optimization, and the goal is to minimize the number of colours used, which is known as
the chromatic number of the graph.
11
ITECH WORLD AKTU
• The chromatic polynomial of a graph counts the number of ways to colour the graph
using at most k colours.
N-Queen Problem
The N-Queen Problem is a classic combinatorial problem where the goal is to place n
queens on an n × n chessboard such that no two queens threaten each other. This means
no two queens can be placed in the same row, column, or diagonal.
Pseudocode:
Algorithm:
1. Start from the first row and place a queen in the first valid column.
3. If no valid position is found in a row, backtrack to the previous row and move the
queen.
4. Continue this process until a solution is found or all possibilities are exhausted.
12
ITECH WORLD AKTU
Backtracking Algorithm:
1. Start with an empty subset and explore all possible subsets by either including or
excluding each element.
• Define a boolean DP table dp[i][j] where i is the index of the set and j is the sum.
• The value of dp[i][j] will be true if there exists a subset with sum j using the first
i elements.
13
ITECH WORLD AKTU
1. Definition: A Hamiltonian circuit is a cycle that visits every vertex exactly once
and returns to the starting vertex.
14
ITECH WORLD AKTU
Syllabus
• Algebraic Computation
• String Matching
• Theory of NP-Completeness
• Approximation Algorithms
• Randomized Algorithms
1
ITECH WORLD AKTU
1. Algebraic Computation
Algebraic computation involves solving polynomial equations, symbolic computation, and
manipulating algebraic structures. It is crucial in algorithm design, especially for prob-
lems in computational geometry, cryptography, and more.
FFT
Fast Fourier Transform (FFT) is an efficient algorithm for computing the Discrete Fourier
Transform (DFT) and its inverse. It reduces the time complexity from O(n2 ) to O(n log n)
by recursively breaking down a DFT of any composite size n into many smaller DFTs.
To compute this efficiently, FFT splits the DFT into smaller sub-problems using the
divide-and-conquer approach. Specifically, the DFT of an n-point sequence is divided
into two n/2-point DFTs:
n/2−1
X
x2j · e−2πijk/n/2 + x2j+1 · e−2πi(j+n/2)k/n .
X(k) =
j=0
Here, x2j represents the even-indexed terms, and x2j+1 represents the odd-indexed terms.
This results in:
X(k) = E(k) + e−2πik/n O(k),
X(k + n/2) = E(k) − e−2πik/n O(k),
where E(k) is the DFT of the even-indexed terms, and O(k) is the DFT of the odd-
indexed terms. This recursive approach continues until n becomes 1.
Algorithm FFT(x)
Input: Array x of n complex numbers, where n is a power of 2.
Output: Array X of n complex numbers, the DFT of x.
if n = 1 then
return x
else
X_even = FFT(x[0], x[2], ..., x[n-2])
X_odd = FFT(x[1], x[3], ..., x[n-1])
for k = 0 to n/2 - 1 do
2
ITECH WORLD AKTU
t = X_odd[k] * exp(-2 * pi * i * k / n)
X[k] = X_even[k] + t
X[k + n/2] = X_even[k] - t
end for
return X
This algorithm recursively breaks down the problem until the input size becomes 1,
then combines the results of smaller DFTs to produce the final output.
Applications of FFT
FFT has numerous applications in different fields, including:
• Signal Processing: FFT is widely used to transform time-domain signals into
their frequency-domain representations, enabling analysis and filtering of signals.
• Image Processing: In image processing, FFT is used to perform operations like
image filtering, compression, and convolution.
• Audio Compression: FFT is essential in audio compression algorithms, such as
MP3 encoding, where it helps to convert sound waves into frequency components.
• Solving Partial Differential Equations: FFT is utilized in numerical methods
for solving partial differential equations (PDEs) like the heat equation and wave
equation, where it accelerates convolution operations.
3. String Matching
String matching involves finding all occurrences of a pattern P within a given text T . It is
crucial in various applications like searching within documents, DNA sequence analysis,
and pattern recognition.
3
ITECH WORLD AKTU
Definitions
(a) String: A string is a sequence of characters, denoted as S, which can include
letters, numbers, or symbols. Example: S = ”abcde”.
(b) Substring: A substring of a string is any contiguous sequence of characters
within the original string. Example: Substrings of S = ”abcde” include ”abc”,
”bcd”, and ”de”.
(c) Proper Substring: A proper substring is a substring that is not equal to the
entire string. Example: For S = ”abcde”, ”abc” is a proper substring, but
”abcde” is not.
(d) Length of String: The length of a string S is the total number of characters
in it. For S = ”abcde”, |S| = 5.
(e) Prefix: A prefix of a string is a substring that starts from the beginning of
the string. Example: For S = ”abcde”, ”a” and ”abc” are prefixes.
(f) Suffix: A suffix of a string is a substring that ends at the end of the string.
Example: For S = ”abcde”, ”de” and ”cde” are suffixes.
(g) Overlapping Patterns: String matching can involve overlapping patterns,
where multiple occurrences of P overlap within T .
(a) Naive String Matching Algorithm: Compares the pattern with every
possible position in the text.
(b) Rabin-Karp Algorithm: Uses hashing to find the pattern efficiently.
(c) Knuth-Morris-Pratt (KMP) Algorithm: Pre-processes the pattern to
create a prefix function, reducing unnecessary comparisons.
Algorithm NaiveStringMatcher(T, P)
Input: Text T of length n, Pattern P of length m
Output: All starting indices where P occurs in T
for s = 0 to n - m do
if T[s:s+m] == P then
print "Pattern occurs at index", s
Rabin-Karp Algorithm
This algorithm computes hash values for the pattern and substrings of the text,
allowing for faster matching. However, it is susceptible to hash collisions.
4
ITECH WORLD AKTU
The KMP algorithm matches the pattern efficiently, resulting in an optimal search
time.
Pattern: P = "abacab"
Indices: 0 1 2 3 4 5
a b a c a b
Prefix Function : [0, 0, 1, 0, 1, 2]
Step-by-Step Calculation of π
(a) π[0] = 0 because ”a” has no proper prefix.
(b) π[1] = 0 because ”b” does not match with ”a”.
(c) π[2] = 1 because ”a” matches with the prefix ”a”.
(d) π[3] = 0 because ”c” does not match with any prefix.
(e) π[4] = 1 because ”a” matches with the prefix ”a”.
(f) π[5] = 2 because ”ab” matches with the prefix ”ab”.
Thus, the prefix function π for P = ”abacab” is [0, 0, 1, 0, 1, 2], which helps in
determining the next positions to continue matching.
5
ITECH WORLD AKTU
4. Theory of NP-Completeness
NP-completeness is a class of problems for which no known polynomial-time solution
exists, but a solution can be verified in polynomial time. Key concepts include NP,
P, and the famous problem of P = N P .
What is NP-Completeness?
• NP-Completeness refers to a category of decision problems for which any prob-
lem can be reduced to another NP problem in polynomial time.
• It is the intersection of NP and NP-Hard problem classes.
• If any NP-Complete problem has a polynomial-time solution, all NP problems
would also be solvable in polynomial time.
• The concept was introduced by Stephen Cook and Richard Karp through the
Cook-Levin theorem.
6
ITECH WORLD AKTU
7
ITECH WORLD AKTU
(a) Show that the problem belongs to NP, as a given solution can be verified in
polynomial time.
(b) Reduce an existing NP-Complete problem (such as 3-SAT) to the Hamiltonian
Circuit problem.
(c) The reduction shows that solving the Hamiltonian Circuit also solves the 3-
SAT problem, proving its NP-Completeness.
8
ITECH WORLD AKTU
• To prove TSP is NP-Hard, reduce the Hamiltonian Cycle problem to the TSP.
• Construct a complete graph from the given graph, with a distance of 1 between
connected vertices and 2 for others.
• The reduction shows that a solution to TSP would also solve the Hamiltonian
Cycle problem.
5. Approximation Algorithms
Approximation algorithms provide near-optimal solutions for NP-hard problems
within a guaranteed factor of the optimal solution. These algorithms are particu-
larly useful when finding the exact solution is computationally infeasible.
9
ITECH WORLD AKTU
10
ITECH WORLD AKTU
• Example: If the MST of a set of cities costs 10, the approximate TSP solution
using this method would cost at most 20.
11
ITECH WORLD AKTU
6. Randomized Algorithms
Randomized algorithms use random numbers at some point in their logic to make
decisions. These algorithms are often used when deterministic approaches are inef-
ficient or overly complex. They can provide a simpler or faster solution to certain
computational problems.
12
ITECH WORLD AKTU
13
ITECH WORLD AKTU
14