module-2
module-2
• Linear search is a simple algorithm to find a target value within a list by checking
each element sequentially.
Algorithm Steps
1. Start from the first element of the list.
2. Compare the current element with
the target:
• If it matches, return its index.
• If not, move to the next element.
3. Repeat step 2 until:
1. The element is found (return the
index), or
2. The end of the list is reached
(return a value indicating not
found, e.g., -1).
Linear Search Algorithm
Performance
Time Complexity:
• Best Case: O(1) (if the target is the first element).
• Worst Case: O(n) (if the target is not found or is the last element).
• Average Case: O(n).
When to Use
• Use linear search when:
• The list is unsorted.
• The dataset is small.
• It is less efficient than binary search but works on any list, regardless of sorting.
• When you are searching for a dataset stored in contiguous memory.
Linear Search Algorithm
• Unsorted Lists: When we have an unsorted array or list, linear search is most
commonly used to find any element in the collection.
• Small Data Sets: Linear Search is preferred over binary search when we have small
data sets.
• Linear search can be used irrespective of whether the array is sorted or not. It can
be used on arrays of any data type.
• Does not require any additional memory.
• It is a well-suited algorithm for small datasets.
• Linear search has a time complexity of O(N), which in turn makes it slow for large
datasets.
• Not suitable for large arrays.
Binary Search Algorithm
• Binary search is an efficient algorithm for finding a target value in a sorted array.
• It works by repeatedly dividing the search interval in half.
• The idea of binary search is to use the information that the array is sorted and
reduce the time complexity to O(log N).
Algorithm Steps
1. Start with two pointers:
• low pointing to the first element.
• high pointing to the last element.
2. Calculate the middle index:
mid=⌊(low+high)/2⌋
3. Compare the middle element with the target:
• If it matches, return the index.
• If the target is smaller, search in the left half by updating high = mid - 1.
• If the target is larger, search in the right half by updating low = mid + 1.
4. Repeat until low > high or the element is found.
5. If the search completes without finding the target, return a value indicating not
found (e.g., -1).
Binary Search Algorithm
Binary Search Algorithm
Performance
• Time Complexity:
• Best Case: O(1) (when the target is at the middle).
• Worst Case: O(logn) (dividing the search space in half at each step).
• Average Case: O(logn).
When to Use
• Use binary search when:
• The dataset is sorted.
• You need efficient searching with large datasets.
Binary Search Algorithm
• Binary search can be used as a building block for more complex algorithms used in
machine learning, such as algorithms for training neural networks or finding the
optimal hyperparameters for a model.
• It can be used for searching in computer graphics such as algorithms for ray tracing
or texture mapping.
• It can be used for searching a database.
Binary Search Algorithm
• Insertion sort is a simple sorting algorithm that works by iteratively inserting each
element of an unsorted list into its correct position in a sorted portion of the list.
• It is like sorting playing cards in your hands. You split the cards into two groups:
the sorted cards and the unsorted cards. Then, you pick a card from the unsorted
group and put it in the right place in the sorted group.
Insertion Sort
Algorithm Steps
1. Assume the first element is already
sorted.
2. For each subsequent element:
• Compare it with elements in the
sorted portion of the array.
• Shift all larger elements one
position to the right.
• Insert the current element in its
correct position in the sorted
portion.
3. Repeat until all elements are sorted.
Insertion Sort
Insertion Sort
Performance
• Time Complexity:
• Best Case: O(n) (when the array is already sorted).
• Worst Case: O(n2) (when the array is sorted in reverse order).
• Average Case: O(n2) .
When to Use
• Insertion sort is best suited for:
• Small datasets.
• Datasets that are already partially sorted.
• It is easy to implement and understand, making it ideal for teaching purposes or
simple use cases.
Divide-and-Conquer
Algorithm Steps
• Choose a Pivot: Pick an element as the pivot (commonly the first, last, or
middle element).
• Partition:
• Rearrange the array so all elements smaller than the pivot are on its
left, and all larger elements are on its right.
• The pivot is now in its correct sorted position.
• Recursion:
• Recursively apply quick sort to the subarrays on the left and right of
the pivot.
Quick sort
Quick sort
Quick sort
Time Complexity
• Best case: O(nlogn) (when the partition is balanced).
Space Complexity
• In-place sorting: O(logn) due to recursive stack space.
Quick sort
Advantages of Quick Sort
• It is a divide-and-conquer algorithm that makes it easier to solve problems.
• It is efficient on large data sets.
• It has a low overhead, as it only requires a small amount of memory to function.
• It is Cache Friendly as we work on the same array to sort and do not copy data to any
auxiliary array.
• Fastest general purpose algorithm for large data when stability is not required.
• It is tail recursive and hence all the tail call optimization can be done.
• Efficient for sorting large datasets with O(n log n) average-case time complexity.
• Used in partitioning problems like finding the kth smallest element or dividing arrays
by pivot.
• Integral to randomized algorithms, offering better performance than deterministic
approaches.
• Applied in cryptography for generating random permutations and unpredictable
encryption keys.
• Partitioning step can be parallelized for improved performance in multi-core or
distributed systems.
• Important in theoretical computer science for analyzing average-case complexity and
developing new techniques.
Merge Sort
• Merge sort is a popular sorting algorithm known for its efficiency and stability.
• It follows the divide-and-conquer approach to sort a given array of elements.
• Here’s a step-by-step explanation of how merge sort works:
– Divide: Divide the list or array recursively into two halves until it can no more
be divided.
– Conquer: Each subarray is sorted individually using the merge sort algorithm.
– Merge: The sorted subarrays are merged back together in sorted order. The
process continues until all elements from both subarrays have been merged.
Merge Sort
Merge Sort
Merge Sort
Merge Sort
Merge Sort
• T(n) Represents the total time time taken by the algorithm to sort an array of size n.
• 2T(n/2) represents time taken by the algorithm to recursively sort the two halves of
the array. Since each half has n/2 elements, we have two recursive calls with input
size as (n/2).
• O(n) represents the time taken to merge the two sorted halves
Merge Sort
Time Complexity:
• Best Case: O(n log n), When the array is already sorted or nearly sorted.
• Average Case: O(n log n), When the array is randomly ordered.
• Worst Case: O(n log n), When the array is sorted in reverse order.
Auxiliary Space: O(n), Additional space is required for the temporary array used during
merging.
Merge Sort
1. Based on Direction:
• Undirected Graph: Edges have no direction. (u,v) implies you can travel
from u to v and vice versa.
• Directed Graph (Digraph): Edges have direction. (u,v) implies you can travel
from u to v, but not necessarily the reverse.
2. Based on Weight:
• Unweighted Graph: All edges are treated equally (no weights).
• Weighted Graph: Each edge has a weight, representing cost, distance, or some
other value.
Types of Graphs
3. Based on Connectivity:
• Connected Graph: There is a path between any two vertices.
• Disconnected Graph: Not all vertices are connected by a path.
• Strongly Connected Graph (Directed): Every vertex is reachable from every other
vertex.
• Weakly Connected Graph (Directed): If the directions of edges are ignored, the
graph becomes connected.
4. Special Types:
• Cyclic Graph: Contains at least one cycle (a path where the starting and ending
vertices are the same).
• Acyclic Graph: Contains no cycles.
• Tree: A connected acyclic graph.
• Bipartite Graph: Vertices can be divided into two sets such that every edge connects
a vertex from one set to the othe
Graph Representation
1. Adjacency Matrix:
A 2D array where matrix[i][j]=1 indicates an edge between
vertices i and j (or the weight if weighted).
Space Complexity: O(V2), where V is the number of vertices.
2. Adjacency List
A list of lists where list[i] contains all neighbors of vertex i.
Space Complexity: O(V+E), where E is the number of edges.
3. Edge List
A list of edges (u,v), optionally with weights.
Space Complexity: O(E).
Breadth-First Search (BFS)
• Breadth-First Search (BFS) is a graph traversal algorithm that explores all the vertices
of a graph or tree layer by layer.
• BFS is used to find the shortest path in an unweighted graph, check connectivity, or
even solve puzzles.
• It is implemented using a queue data structure.
1. Start at a source node: Begin at the starting node (source) and mark it as
visited.
2. Enqueue the starting node: Add it to the queue.
3. Dequeue and Explore: Remove a node from the queue and examine its
neighbors.
4. Mark and Enqueue Neighbors: For each unvisited neighbor of the
dequeued node:
• Mark it as visited.
• Enqueue it.
5. Repeat until queue is empty: Continue dequeuing and processing nodes
until the queue is empty.
Breadth-First Search (BFS)
Breadth-First Search (BFS)
Breadth-First Search (BFS)
BFS has various applications in graph theory and computer science, including:
• Shortest Path Finding: BFS can be used to find the shortest path between two nodes
in an unweighted graph. By keeping track of the parent of each node during the
traversal, the shortest path can be reconstructed.
• Cycle Detection: BFS can be used to detect cycles in a graph. If a node is visited twice
during the traversal, it indicates the presence of a cycle.
• Level Order Traversal of Binary Trees: BFS can be used to perform a level order
traversal of a binary tree. This traversal visits all nodes at the same level before
moving to the next level.
• Network Routing: BFS can be used to find the shortest path between two nodes in a
network, making it useful for routing data packets in network protocols.
Depth-First Search (DFS)
• Depth-First Search (DFS) is a graph traversal algorithm that explores as far down a
branch as possible before backtracking to explore other branches.
• It is often implemented using recursion or a stack data structure.
• Time complexity: O(V + E). time complexity is same here because we visit every
vertex at most once and every edge is traversed at most once (in directed) and twice
in undirected.
• Auxiliary Space: O(V + E), since an extra visited array of size V is required, And stack
size for recursive calls to DFSRec function.
• Traversal Order: Goes deep into one branch before switching to another
Depth-First Search (DFS)
Applications of DFS
• Cycle Detection: Identify cycles in a graph.
• Topological Sorting: For Directed Acyclic Graphs (DAGs).
• Pathfinding: Explore possible paths (e.g., maze solving).
• Connectivity Testing: Check if a graph is connected.
• Component Detection: Find connected components in undirected graphs.