diff --git a/divide_and_conquer/QuickSort.py b/divide_and_conquer/QuickSort.py new file mode 100644 index 000000000000..23555c065908 --- /dev/null +++ b/divide_and_conquer/QuickSort.py @@ -0,0 +1,19 @@ +def quicksort(arr): + # Base case: If the array has 0 or 1 element, it's already sorted + if len(arr) <= 1: + return arr + + # Choosing the pivot (we pick the last element) + pivot = arr[-1] + + # Dividing elements into two lists: smaller than pivot and greater than pivot + smaller = [x for x in arr[:-1] if x <= pivot] + larger = [x for x in arr[:-1] if x > pivot] + + # Recursively apply quicksort to the smaller and larger parts + return quicksort(smaller) + [pivot] + quicksort(larger) + +# Example usage +arr = [3, 6, 8, 10, 1, 2, 1] +sorted_arr = quicksort(arr) +print(sorted_arr) diff --git a/graphs/edmond_blossom_algo_max_matching.py b/graphs/edmond_blossom_algo_max_matching.py new file mode 100644 index 000000000000..45162c5ae1b1 --- /dev/null +++ b/graphs/edmond_blossom_algo_max_matching.py @@ -0,0 +1,65 @@ +from collections import deque + +# Function to find the augmenting path in the graph using BFS +def find_augmenting_path(graph, matching, dist, u, parent): + queue = deque([u]) + dist[u] = 0 + + while queue: + u = queue.popleft() + + for v in graph[u]: + if matching[v] is None: # Found an augmenting path + parent[v] = u + return v + + if dist[matching[v]] is None: + dist[matching[v]] = dist[u] + 1 + parent[matching[v]] = u + queue.append(matching[v]) + + return None + +# Function to trace back the augmenting path and update the matching +def augment_path(matching, parent, v): + while v is not None: + u = parent[v] + matching[v] = u + matching[u] = v + v = parent[u] + +# Main function implementing Edmonds' Blossom Algorithm +def edmonds_blossom(graph, n): + matching = [None] * n # None indicates unmatched vertices + + for u in range(n): + if matching[u] is None: # Try to match this vertex + dist = [None] * n + parent = [None] * n + + v = find_augmenting_path(graph, matching, dist, u, parent) + if v is not None: + augment_path(matching, parent, v) + + return matching + +# Example usage +if __name__ == "__main__": + # Example graph: adjacency list representation + graph = { + 0: [1, 2], + 1: [0, 2, 3], + 2: [0, 1], + 3: [1], + 4: [5], + 5: [4] + } + + n = len(graph) + matching = edmonds_blossom(graph, n) + + # Print the matching + print("Maximum Matching:") + for u in range(n): + if matching[u] is not None and u < matching[u]: + print(f"{u} -- {matching[u]}") diff --git a/graphs/kruskal_algo.py b/graphs/kruskal_algo.py new file mode 100644 index 000000000000..e34716193841 --- /dev/null +++ b/graphs/kruskal_algo.py @@ -0,0 +1,77 @@ +# Kruskal's Algorithm in Python + +# Class to represent a graph +class Graph: + def __init__(self, vertices): + self.V = vertices # Number of vertices + self.graph = [] # List to store the graph edges (u, v, w) + + # Add edges to the graph + def add_edge(self, u, v, w): + self.graph.append([u, v, w]) + + # Utility function to find the subset of an element 'i' + def find(self, parent, i): + if parent[i] == i: + return i + return self.find(parent, parent[i]) + + # Utility function to do union of two subsets + def union(self, parent, rank, x, y): + root_x = self.find(parent, x) + root_y = self.find(parent, y) + + # Attach smaller rank tree under root of higher rank tree + if rank[root_x] < rank[root_y]: + parent[root_x] = root_y + elif rank[root_x] > rank[root_y]: + parent[root_y] = root_x + else: + parent[root_y] = root_x + rank[root_x] += 1 + + # The main function to implement Kruskal's algorithm + def kruskal_mst(self): + result = [] # This will store the resultant MST + i, e = 0, 0 # Variables for sorted edges and result array + + # Sort all the edges in ascending order based on their weight + self.graph = sorted(self.graph, key=lambda item: item[2]) + + parent = [] + rank = [] + + # Create V subsets with single elements + for node in range(self.V): + parent.append(node) + rank.append(0) + + # Number of edges in MST will be V-1 + while e < self.V - 1: + + # Pick the smallest edge and increment the index for the next iteration + u, v, w = self.graph[i] + i = i + 1 + x = self.find(parent, u) + y = self.find(parent, v) + + # If including this edge doesn't cause a cycle, include it in the result + if x != y: + e = e + 1 + result.append([u, v, w]) + self.union(parent, rank, x, y) + + # Print the contents of the resultant MST + print("Edges in the constructed MST:") + for u, v, weight in result: + print(f"{u} -- {v} == {weight}") + +# Driver code +g = Graph(4) +g.add_edge(0, 1, 10) +g.add_edge(0, 2, 6) +g.add_edge(0, 3, 5) +g.add_edge(1, 3, 15) +g.add_edge(2, 3, 4) + +g.kruskal_mst()