Dsa Cheatsheet Mastery 1695728264

Download as pdf or txt
Download as pdf or txt
You are on page 1of 22

15 Days Data Structures Mastery Cheat Sheet

Introduction
This guide serves as a comprehensive introduction to data structures, a critical topic for anyone
looking to become proficient in computer science and software development. By the end of this
15-day journey, you will have a strong foundation and hands-on experience with various data
structures.

Target Audience

This guide is designed to cater to a broad audience, including but not limited to:

• Students looking for academic excellence or preparing for technical interviews


• Software professionals wanting to deepen their understanding of data structures for
better coding practices
• Hobbyists and self-learners who are passionate about programming

No prior experience is required, although a basic understanding of programming concepts will


significantly enhance the learning process.

Learning Outcomes

Upon completion of this 15-day guide, you will:

1. Understand Various Data Structures: Gain a deep understanding of arrays, linked lists, stacks,
queues, trees, graphs, and more.

2. Analyze Algorithms: Be capable of analyzing the time and space complexities of algorithms
that manipulate these data structures.

3. Problem-Solving Skills: Develop the ability to solve complex problems related to data storage,
retrieval, and manipulation.

4. Hands-on Experience: Acquire practical skills through coding exercises, examples, and mini-
projects.

5. Preparation for Interviews: Be well-prepared for technical interviews that focus on data
structures and algorithms.
Day 1: Introduction to Data Structures
Topics Covered

What are Data Structures?


In computer science, a data structure is a particular way of organizing and storing data in a
computer so that it can be accessed and modified efficiently. Understanding data structures is
crucial for writing efficient code and building software applications. This section will introduce
you to the concept and its importance in computer science.

Types of Data Structures


Data structures can be broadly classified into two types: linear and non-linear. Linear data
structures include arrays, linked lists, stacks, and queues. Non-linear data structures include
trees, graphs, heaps, and more. This section provides an overview of these types and how they
differ from each other.

In-depth Explanation

What are Data Structures?


• Importance: Efficient data storage and retrieval, optimal use of resources.
• Applications: Databases, Operating Systems, Networking, and more.

Types of Data Structures


• Linear Data Structures: Data elements are arranged in a sequence.
• Array: Fixed-size, contiguous memory allocation.
• Linked List: Dynamic size, non-contiguous memory allocation.
• Non-linear Data Structures: Hierarchical storage of data.
• Trees: Parent-child relationship between nodes.
• Graphs: Network of interconnected nodes.

Exercises

1. Define a Simple Array in Python


Objective: To understand the basics of array data structure.

Code Snippet:
my_array = [1, 2, 3, 4, 5]

Explanation: This is a simple Python array containing five elements.


2. Implement a Linked List Node in Python
Objective: To grasp the fundamentals of linked lists.

Code Snippet:
class Node:
def __init__(self, data):
self.data = data
self.next = None

Explanation: The `Node` class represents a single node in a linked list. It has two properties:
`data`, which stores the value, and `next`, which points to the next node in the list.

-------------------------------------------------------------------------------------------------------------------------------

Day 2: Arrays and Strings


Topics Covered

Basics of Arrays
An array is a collection of elements identified by index or key. They are one of the simplest data
structures and serve as the building blocks for more complex types. This section will cover the
basic properties, operations, and applications of arrays.

Manipulating Strings
Strings are arrays of characters. Understanding how to manipulate strings is crucial for tasks
ranging from parsing text to algorithms like pattern matching. This section covers common
string operations such as reversing, concatenation, and substring extraction.

In-depth Explanation

Basics of Arrays
• Properties: Fixed-size, contiguous memory allocation.
• Operations: Insertion, deletion, traversal, and search.
• Applications: Used in multiple dimensions in matrices, used as buffers in various data
stream algorithms.

Manipulating Strings
• Properties: Immutable or mutable based on the language.
• Operations: Finding length, substring, concatenation, and reversal.
• Applications: Text processing, string matching algorithms, and natural language
processing tasks.

Exercises

1. Write a Python program to reverse an array

Objective: To understand array traversal and manipulation.

Code Snippet:
def reverse_array(arr):
return arr[::-1]

Explanation: This Python function takes an array as input and returns a new array with the
elements in reverse order.

2. Write a Python program to check for a palindrome string

Objective: To apply string manipulation techniques.

Code Snippet:
def is_palindrome(s):
return s == s[::-1]

Explanation: This Python function checks if a given string is a palindrome. A palindrome is a


word, phrase, number, or other sequences of characters that reads the same forward and
backward (ignoring spaces, punctuation, and capitalization).

-------------------------------------------------------------------------------------------------------------------------------

Day 3: Linked Lists


Topics Covered

Singly Linked List


A singly linked list is a type of data structure that is made up of nodes that are created using
self-referential structures. Each node contains data and a reference (link) to the next node in
the sequence.
Doubly Linked List
A doubly linked list is similar to a singly linked list, but each node contains a reference to both
the next node and the previous node in the sequence.

In-depth Explanation

Singly Linked List


• Properties: Nodes in a singly linked list contain data and a next pointer.
• Operations: Insertion at head/tail, deletion, traversal, and search.
• Applications: Useful in data structures like stacks and queues, and in algorithms like
polynomial addition and algorithmic problem-solving.

Doubly Linked List


• Properties: Nodes contain data, a next pointer, and a previous pointer.
• Operations: Insertion at head/tail, deletion from head/tail, traversal, and search.
• Applications: Useful in data structures like deque and in algorithms that require
backward traversal.

Exercises

1. Implement a Singly Linked List in Python


Objective: To understand the basic operations of a singly linked list.

Code Snippet:
class Node:
def __init__(self, data):
self.data = data
self.next = None

class SinglyLinkedList:
def __init__(self):
self.head = None

Explanation: The `Node` class represents the nodes in the list, while the `SinglyLinkedList` class
contains a head pointer to the first node in the list.

2. Write a Python program to delete a node in a Doubly Linked List


Objective: To understand deletion operations in a doubly linked list.

Code Snippet:
def delete_node(self, node):
if self.head is None:
return
if self.head == node:
self.head = node.next
if node.next is not None:
node.next.prev = node.prev
if node.prev is not None:
node.prev.next = node.next

Explanation: The `delete_node` method deletes a given node from a doubly linked list. It adjusts
the next and previous pointers of adjacent nodes to remove the target node.

-------------------------------------------------------------------------------------------------------------------------------

Day 4: Stacks
Topics Covered

Introduction to Stacks
A stack is a linear data structure that follows the Last In, First Out (LIFO) principle. It's like a
collection of elements with two main operations: Push, which adds an element to the
collection, and Pop, which removes the most recently added element.

Stack Operations: Push, Pop, Peek


The section elaborates on the primary operations involved in a stack—Push, Pop, and Peek.
Push adds an element at the top, Pop removes the top element, and Peek merely views the top
element without removing it.

In-depth Explanation

Introduction to Stacks
- Properties: LIFO principle, dynamic size.

- Applications: Parsing expressions, backtracking algorithms, function calls in recursive


algorithms.

Stack Operations: Push, Pop, Peek


- Push: Adds an element at the top of the stack.

- Pop: Removes and returns the top element from the stack.

- Peek: Returns the top element without removing it.


Exercises
1. Implement a Stack using an Array in Python
Objective: To understand the basic operations of a stack using arrays.

Code Snippet:
class Stack:
def __init__(self):
self.stack = []
def push(self, item):
self.stack.append(item)

Explanation: The `Stack` class uses an array (list in Python) to implement the stack. The `push`
method appends an item to the end of the list, effectively pushing it onto the stack.

2. Implement a Stack using a Linked List in Python


Objective: To understand the basic operations of a stack using linked lists.

Code Snippet:
class Node:
def __init__(self, data):
self.data = data
self.next = None
class Stack:
def __init__(self):
self.top = None
def push(self, data):
new_node = Node(data)
new_node.next = self.top
self.top = new_node

Explanation: The `Stack` class uses a linked list to implement the stack. The `push` method
creates a new node and adjusts the `top` pointer to add the new node to the stack.

Day 5: Queues
Topics Covered

Introduction to Queues
A queue is a linear data structure that follows the First In, First Out (FIFO) principle. Unlike a
stack, a queue adds elements to the end and removes them from the beginning, ensuring that
the first element added is also the first to be removed.
Queue Operations: Enqueue, Dequeue, Front
This section covers the basic operations associated with a queue—Enqueue, Dequeue, and
Front. Enqueue adds an element to the end of the queue, Dequeue removes the element from
the front, and Front allows you to view the front element without removing it.

In-depth Explanation

Introduction to Queues
• Properties: FIFO principle, dynamic size.
• Applications: Scheduling algorithms, maintaining a playlist, and in algorithms where
order needs to be maintained.

Queue Operations: Enqueue, Dequeue, Front


• Enqueue: Adds an element at the end of the queue.
• Dequeue: Removes and returns the front element from the queue.
• Front: Returns the front element without removing it.

Exercises

1. Implement a Queue using an Array in Python


Objective: To understand the basic operations of a queue using arrays.

Code Snippet:
class Queue:
def __init__(self):
self.queue = []
def enqueue(self, item):
self.queue.append(item)

Explanation: The `Queue` class uses an array (Python list) to implement the queue. The
`enqueue` method appends an item to the end of the list, effectively adding it to the queue.

2. Implement a Priority Queue in Python

• Objective: To understand the concept of priority in a queue.


• Code Snippet:

Code Snippet:
import heapq
class PriorityQueue:
def __init__(self):
self.queue = []
def enqueue(self, item, priority):
heapq.heappush(self.queue, (priority, item))

Explanation: The `PriorityQueue` class uses a heap to implement a queue where elements can
have priorities. The `enqueue` method adds an item along with its priority to the heap.

-------------------------------------------------------------------------------------------------------------------------------

Day 6: Trees
Topics Covered

Binary Trees
A binary tree is a tree data structure in which each node has at most two children, commonly
referred to as the "left" and "right" child. This section provides an overview of binary trees and
how they work.

Binary Search Trees


A binary search tree (BST) is a specific type of binary tree that has the property that the key in
each node must be greater than all keys stored in the left sub-tree, and smaller than all keys in
the right sub-tree.

In-depth Explanation

Binary Trees
• Properties: Hierarchical structure, parent-child relationship.
• Operations: Insertion, deletion, traversal (In-order, Pre-order, Post-order).
• Applications: Used in algorithms like heapsort, and data structures like binary heaps.

Binary Search Trees


• Properties: Ordered arrangement of elements.
• Operations: Insertion, deletion, search, traversal.
• Applications: Used in databases for faster search and retrieval operations.

Exercises

1. Implement a Binary Tree in Python


Objective: To understand the hierarchical structure and basic operations in a binary tree.

Code Snippet:
class Node:
def __init__(self, key):
self.left = None
self.right = None
self.val = key

Explanation: The `Node` class represents the nodes in the binary tree. Each node has a left
child, a right child, and a value.

2. Write a Python program to search for an element in a Binary Search Tree


Objective: To understand search operations in a binary search tree.

Code Snippet:
def search(root, key):
if root is None or root.val == key:
return root
if root.val < key:
return search(root.right, key)
return search(root.left, key)

Explanation: The `search` function recursively searches for a given key in a binary search tree. It
navigates through the tree based on the value of each node compared to the key.

-------------------------------------------------------------------------------------------------------------------------------

Day 7: Hash Tables


Topics Covered

Introduction to Hash Tables


A hash table is a data structure that stores key-value pairs. It uses a hash function to compute
an index into an array of buckets or slots, from which the desired value can be found.

Collision Resolution Techniques


In hash tables, collision occurs when two keys hash to the same index. This section will discuss
various techniques to resolve collisions, such as chaining and open addressing.

In-depth Explanation

Introduction to Hash Tables


• Properties: Fast access, key-value storage.
• Operations: Insertion, deletion, search.
• Applications: Used in databases for quick data retrieval, caching mechanisms, and more.
Collision Resolution Techniques
• Chaining: Uses an additional data structure (usually a linked list) to store multiple items
that hash to the same index.
• Open Addressing: Searches for the next open slot or address in the hash table.

Exercises

1. Implement a Hash Table in Python


Objective: To understand the key-value pair storage and basic operations in a hash table.

Code Snippet:
class HashTable:
def __init__(self):
self.size = 10
self.table = [None] * self.size

Explanation: The `HashTable` class initializes a table of a fixed size (10 in this case). Each index
of the table will contain the values for keys that hash to that index.

2. Write a Python program to handle hash collisions using chaining


Objective: To understand collision resolution in a hash table.

Code Snippet:
def insert(self, key, value):
index = hash(key) % self.size
if self.table[index] is None:
self.table[index] = [(key, value)]
else:
self.table[index].append((key, value))

Explanation: The `insert` method calculates the index using the hash of the key and adds the
key-value pair to that index. If the index already contains other key-value pairs, it appends the
new pair to the list, effectively using chaining to resolve collisions.

-------------------------------------------------------------------------------------------------------------------------------
Day 8: Graphs
Topics Covered

Directed Graphs
A directed graph, also called a digraph, is a set of vertices and a collection of directed edges.
Each edge has a direction, meaning it goes from one vertex to another, not the other way
around.

Undirected Graphs
In an undirected graph, edges have no direction. That is, if an edge goes from vertex A to vertex
B, it also goes from vertex B to vertex A.

In-depth Explanation

Directed Graphs
• Properties: Vertices and directed edges.
• Operations: Insertion of vertices and edges, traversal (DFS, BFS).
• Applications: Used in network routing, social networks, and many other scenarios.

Undirected Graphs
• Properties: Vertices and undirected edges.
• Operations: Insertion of vertices and edges, traversal (DFS, BFS).
• Applications: Used in network design, pathfinding algorithms, and many more.

Exercises

1. Implement a Graph using an Adjacency List in Python


Objective: To understand the structure and basic operations of a graph using an adjacency list.

Code Snippet:
class Graph:
def __init__(self):
self.graph = {}
def add_edge(self, u, v):
if u not in self.graph:
self.graph[u] = []
self.graph[u].append(v)

Explanation: The `Graph` class uses a dictionary to implement an adjacency list. The `add_edge`
method adds an edge between vertices `u` and `v`.
2. Implement a Graph using an Adjacency Matrix in Python
Objective: To understand the structure and basic operations of a graph using an adjacency
matrix.

Code Snippet:
class Graph:
def __init__(self, vertices):
self.V = vertices
self.graph = [[0 for _ in range(vertices)] for _ in
range(vertices)]
def add_edge(self, u, v):
self.graph[u][v] = 1
self.graph[v][u] = 1

Explanation: The `Graph` class uses a 2D array to implement an adjacency matrix. The
`add_edge` method sets the value at `graph[u][v]` and `graph[v][u]` to 1, indicating an edge.

-------------------------------------------------------------------------------------------------------------------------------

Day 9: Dynamic Programming


Topics Covered

Memoization
Memoization is an optimization technique used to speed up programs by storing the results of
expensive function calls and returning the cached result when the same inputs occur again.

Tabulation
Tabulation is the opposite of the top-down approach and solves the problem in a bottom-up
fashion. It is about solving all the sub-problems first and using their solutions to build-on and
arrive at solutions to bigger sub-problems.

In-depth Explanation

Memoization
• Properties: Caching of results, top-down approach.
• Applications: Used in various algorithms like Fibonacci series, coin change problem, and
more.

Tabulation
• Properties: Solve and store results for all possible small sub-problems, bottom-up
approach.
• Applications: Used in optimization problems like the knapsack problem, shortest paths
in a graph, etc.

Exercises

1. Write a Python program for the Fibonacci series using Memoization


Objective: To understand the concept of memoization in dynamic programming.

Code Snippet:
def fib(n, memo={}):
if n in memo:
return memo[n]
if n <= 2:
return 1
memo[n] = fib(n-1, memo) + fib(n-2, memo)
return memo[n]

Explanation: The `fib` function uses a dictionary called `memo` to store Fibonacci numbers that
are already calculated. This avoids redundant calculations and improves the function's
efficiency.

2. Write a Python program for the Coin Change problem using Tabulation
Objective: To understand the concept of tabulation in dynamic programming.

Code Snippet:
def coinChange(coins, amount):
dp = [float('inf')] * (amount + 1)
dp[0] = 0
for coin in coins:
for x in range(coin, amount + 1):
dp[x] = min(dp[x], dp[x - coin] + 1)
return dp[amount] if dp[amount] != float('inf') else -1

Explanation: The `coinChange` function uses an array `dp` to store the minimum number of
coins needed to make up amounts from 0 to the target amount. This is a bottom-up approach
that fills in `dp` using smaller sub-problems to solve larger ones.

-------------------------------------------------------------------------------------------------------------------------------
Day 10: Sorting Algorithms
Topics Covered

Bubble Sort
Bubble Sort is a simple sorting algorithm that repeatedly steps through the list, compares
adjacent elements, and swaps them if they are in the wrong order.

Quick Sort
Quick Sort is an efficient, in-place sorting algorithm that uses a divide-and-conquer strategy to
sort elements.

In-depth Explanation

Bubble Sort
• Properties: In-place, stable sort.
• Operations: Comparisons and swaps.
• Applications: Suitable for small datasets and educational purposes.

Quick Sort
• Properties: In-place, unstable sort.
• Operations: Partitioning, recursive sorting.
• Applications: Used in various in-memory sorts and has numerous practical applications.

Exercises

1. Implement Bubble Sort in Python


Objective: To understand the mechanics of Bubble Sort.

Code Snippet:
def bubble_sort(arr):
for i in range(len(arr)):
for j in range(0, len(arr)-i-1):
if arr[j] > arr[j+1]:
arr[j], arr[j+1] = arr[j+1], arr[j]

Explanation: The `bubble_sort` function iterates through the array multiple times, swapping
adjacent elements if they are in the wrong order, eventually sorting the array.

2. Implement Quick Sort in Python


Objective: To understand the divide-and-conquer strategy used in Quick Sort.
Code Snippet:
def quick_sort(arr):
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
left = [x for x in arr if x < pivot]
middle = [x for x in arr if x == pivot]
right = [x for x in arr if x > pivot]
return quick_sort(left) + middle + quick_sort(right)

Explanation: The `quick_sort` function selects a 'pivot' element and partitions the array into
three parts: elements less than the pivot, elements equal to the pivot, and elements greater
than the pivot. It then recursively sorts the 'left' and 'right' partitions.

-------------------------------------------------------------------------------------------------------------------------------

Day 11: Searching Algorithms


Topics Covered

Linear Search
Linear search is the simplest searching algorithm that searches for an element within a list in a
sequential manner, one item at a time, without jumping to any item.

Binary Search
Binary search is a fast search algorithm that finds the position of a target value within a sorted
list. It compares the target value to the middle element of the list and eliminates half of the
search interval based on the comparison.

In-depth Explanation

Linear Search
• Properties: Sequential search, no need for sorted data.
• Operations: Element-by-element comparison.
• Applications: Suitable for small and unsorted datasets.

Binary Search
• Properties: Requires sorted data, divides search interval in half at each step.
• Operations: Midpoint calculation, interval division.
• Applications: Used in searching algorithms where computational complexity needs to be
reduced.
Exercises

1. Write a Python program for Linear Search


Objective: To understand the basics of linear search.

Code Snippet:
def linear_search(arr, x):
for i in range(len(arr)):
if arr[i] == x:
return i
return -1

Explanation: The `linear_search` function scans each element of the list one by one and returns
the index of the target element if found, otherwise returns -1.

2. Write a Python program for Binary Search


Objective: To understand the efficiency of binary search in a sorted array.

Code Snippet:
def binary_search(arr, x):
low, high = 0, len(arr) - 1
while low <= high:
mid = (high + low) // 2
if arr[mid] < x:
low = mid + 1
elif arr[mid] > x:
high = mid - 1
else:
return mid
return -1

Explanation: The `binary_search` function takes a sorted array and a target element as input. It
uses two pointers, `low` and `high`, to find the middle element of the array. Depending on the
comparison with the middle element, it adjusts the `low` and `high` pointers.

-------------------------------------------------------------------------------------------------------------------------------

Day 12: Recursion


Topics Covered

Understanding Recursion
Recursion is a technique in programming where a function calls itself. This section will cover the
basic mechanics of recursion and its advantages and disadvantages.

Tail Recursion and Non-Tail Recursion


This section differentiates between tail recursion, where the recursive call is the last operation
in the function, and non-tail recursion, where the function performs an operation after the
recursive call.

In-depth Explanation

Understanding Recursion
• Properties: Self-referential, base and recursive cases.
• Operations: Function calling itself.
• Applications: Used in algorithms like quick sort, depth-first search, and many others.

Tail Recursion and Non-Tail Recursion


• Tail Recursion: Returns the result of the recursive call directly.
• Non-Tail Recursion: Performs additional operations after the recursive call.

Exercises
1. Write a Python program for Factorial using Recursion
Objective: To understand the basic concept of recursion.

Code Snippet:
def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n-1)

Explanation: The `factorial` function calculates the factorial of a number using recursion. It has a
base case when `n` is 0 and a recursive case for other values of `n`.

2. Write a Python program for Fibonacci using Tail Recursion


Objective: To understand the concept of tail recursion.

Code Snippet:
def fib_tail(n, a=0, b=1):
if n == 0:
return a
else:
return fib_tail(n-1, b, a+b)

Explanation: The `fib_tail` function calculates the Fibonacci number at position `n` using tail
recursion. It uses two additional arguments, `a` and `b`, to keep track of the two most recent
numbers in the sequence.

-------------------------------------------------------------------------------------------------------------------------------

Day 13: Advanced Data Structures


Topics Covered

Heaps
A heap is a specialized tree-based data structure that satisfies the heap property. This section
will introduce both min-heaps and max-heaps.

Trie
A Trie, or prefix tree, is a tree-like data structure that is used to store a dynamic set of strings.
Tries are generally used for searching text within a body of text.

In-depth Explanation

Heaps
• Properties: Binary tree for heaps, heap property maintenance.
• Operations: Heapify, insert, delete, and extract min/max.
• Applications: Used in algorithms like heap sort, priority queues, and more.

Trie
• Properties: Tree-like structure, nodes store the keys of a dataset of strings.
• Operations: Insert, search, and delete.
• Applications: Auto-complete features, spell checkers, and routing tables in networking.

Exercises

1. Implement a Min-Heap in Python


Objective: To understand the structure and operations of a min-heap.

Code Snippet:
import heapq
def heapify(arr):
heapq.heapify(arr)

Explanation: The `heapify` function uses Python's built-in `heapq` library to convert an array
into a min-heap.

2. Implement a Trie for String Search in Python


Objective: To understand the structure and operations of a Trie for string storage and retrieval.

Code Snippet:
class TrieNode:
def __init__(self):
self.children = {}
self.is_end_of_word = False

class Trie:
def __init__(self):
self.root = TrieNode()
def insert(self, word):
node = self.root
for char in word:
if char not in node.children:
node.children[char] = TrieNode()
node = node.children[char]
node.is_end_of_word = True

Explanation: The `Trie` class uses a `TrieNode` to build a Trie data structure. The `insert` method
adds a word to the Trie, creating new TrieNodes as needed.

-------------------------------------------------------------------------------------------------------------------------------

Day 14: Algorithmic Paradigms


Topics Covered

Greedy Algorithms
Greedy algorithms build a solution piece by piece, always choosing the next piece that offers
the most immediate benefit or profit.

Divide and Conquer Algorithms


Divide and conquer algorithms break the problem into smaller subproblems, solve the
subproblems, and then combine them to create a solution to the original problem.
In-depth Explanation

Greedy Algorithms
• Properties: Local optimum choices at each step.
• Operations: Iterative selection based on some heuristic.
• Applications: Used in problems like Kruskal's algorithm for minimum spanning tree,
Huffman coding, and more.

Divide and Conquer Algorithms


• Properties: Breaking problems into smaller, similar problems.
• Operations: Recursively solving subproblems and combining them.
• Applications: Used in algorithms like quick sort, merge sort, and binary search.

Exercises

1. Write a Python program for Fractional Knapsack using Greedy Algorithms


Objective: To understand the greedy approach.

Code Snippet:
def fractional_knapsack(value, weight, capacity):
ratio = [v/w for v, w in zip(value, weight)]
index = list(range(len(value)))
index.sort(key=lambda i: ratio[i], reverse=True)
max_value = 0
for i in index:
if capacity >= weight[i]:
max_value += value[i]
capacity -= weight[i]
else:
max_value += value[i] * (capacity / weight[i])
break
return max_value

Explanation: The `fractional_knapsack` function calculates the maximum value that can be
achieved within the given capacity. It sorts the items based on their value-to-weight ratio and
then picks the best items based on this sorted order.

2. Write a Python program for Merge Sort using Divide and Conquer
Objective: To understand the divide and conquer approach.
Code Snippet:
def merge_sort(arr):
if len(arr) <= 1:
return arr
mid = len(arr) // 2
left = arr[:mid]
right = arr[mid:]
return merge(merge_sort(left), merge_sort(right))

Explanation: The `merge_sort` function sorts an array by dividing it into two halves, sorting
each half, and then merging them back together. This is a classic example of a divide and
conquer algorithm.

-------------------------------------------------------------------------------------------------------------------------------

Day 15: Project Work


Mini Projects

Project 1: Social Network Analysis using Graphs

• Objective: Use graph algorithms to analyze social networks.


• Tools: Python, Graph Data Structures

Project 2: Text-based Search Engine using Trie

• Objective: Implement a basic search engine using Trie data structure.


• Tools: Python, Trie Data Structure

You might also like