Skip to content

Commit 1cecf29

Browse files
Added the dsa Programs to the project
1 parent 50c2b34 commit 1cecf29

34 files changed

+934
-0
lines changed

dsa_programs/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# DSA Programs
2+
3+
Thirty standalone algorithm examples, surfaced from the package root:
4+
5+
- `two_sum.py` – hash map pair finder in linear time.
6+
- `binary_search.py` – iterative search on sorted sequences.
7+
- `merge_sort.py` – stable divide-and-conquer sort.
8+
- `quick_select.py` – k-th statistic selection in expected linear time.
9+
- `breadth_first_search.py` – queue-based graph traversal.
10+
- `depth_first_search.py` – recursive graph exploration.
11+
- `topological_sort.py` – Kahn's algorithm for DAG ordering.
12+
- `dijkstra_shortest_path.py` – priority-queue shortest paths.
13+
- `lru_cache.py` – ordered dictionary backed LRU cache.
14+
- `knapsack_01.py` – 0/1 knapsack dynamic program.
15+
- `bellman_ford.py` – edge relaxation with negative-cycle detection.
16+
- `floyd_warshall.py` – all-pairs shortest paths on dense graphs.
17+
- `prim_mst.py` – minimum spanning tree via Prim's algorithm.
18+
- `kruskal_mst.py` – MST construction with union-find.
19+
- `union_find.py` – disjoint-set data structure.
20+
- `segment_tree.py` – range-sum queries with point updates.
21+
- `fenwick_tree.py` – binary indexed tree for prefix sums.
22+
- `trie.py` – prefix tree with search and prefix checks.
23+
- `boyer_moore_majority.py` – majority element by voting.
24+
- `kadane_max_subarray.py` – maximum subarray sum in linear time.
25+
- `dutch_national_flag.py` – three-way partition of 0/1/2 values.
26+
- `heap_sort.py` – heap-based in-place sorting.
27+
- `sieve_of_eratosthenes.py` – prime number generation.
28+
- `reservoir_sampling.py` – uniform streaming sample of size k.
29+
- `sliding_window_maximum.py` – deque based sliding extrema.
30+
- `rabin_karp.py` – rolling hash substring search.
31+
- `kmp_search.py` – prefix-function substring search.
32+
- `manacher_palindrome.py` – longest palindromic substring in linear time.
33+
- `edit_distance.py` – Levenshtein distance dynamic program.
34+
- `longest_common_subsequence.py` – subsequence reconstruction DP.
35+
- `tarjan_scc.py` – strongly connected components in directed graphs.

dsa_programs/__init__.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
"""Core data structures and algorithms examples for quick reference."""
2+
3+
from .bellman_ford import bellman_ford
4+
from .binary_search import binary_search
5+
from .boyer_moore_majority import boyer_moore_majority
6+
from .breadth_first_search import breadth_first_search
7+
from .depth_first_search import depth_first_search
8+
from .dijkstra_shortest_path import dijkstra_shortest_path
9+
from .dutch_national_flag import dutch_national_flag
10+
from .edit_distance import edit_distance
11+
from .fenwick_tree import FenwickTree
12+
from .floyd_warshall import floyd_warshall
13+
from .heap_sort import heap_sort
14+
from .kadane_max_subarray import kadane_max_subarray
15+
from .knapsack_01 import knapsack_01
16+
from .kruskal_mst import kruskal_mst
17+
from .longest_common_subsequence import longest_common_subsequence
18+
from .lru_cache import LRUCache
19+
from .manacher_palindrome import manacher_longest_palindrome
20+
from .merge_sort import merge_sort
21+
from .prim_mst import prim_mst
22+
from .quick_select import quick_select
23+
from .kmp_search import kmp_search
24+
from .rabin_karp import rabin_karp_search
25+
from .reservoir_sampling import reservoir_sample
26+
from .segment_tree import SegmentTree
27+
from .sieve_of_eratosthenes import sieve_of_eratosthenes
28+
from .sliding_window_maximum import sliding_window_maximum
29+
from .tarjan_scc import tarjan_strongly_connected_components
30+
from .topological_sort import topological_sort
31+
from .trie import Trie
32+
from .two_sum import two_sum
33+
from .union_find import UnionFind
34+
35+
__all__ = [
36+
"FenwickTree",
37+
"LRUCache",
38+
"SegmentTree",
39+
"Trie",
40+
"UnionFind",
41+
"bellman_ford",
42+
"binary_search",
43+
"boyer_moore_majority",
44+
"breadth_first_search",
45+
"depth_first_search",
46+
"dijkstra_shortest_path",
47+
"dutch_national_flag",
48+
"edit_distance",
49+
"floyd_warshall",
50+
"heap_sort",
51+
"kadane_max_subarray",
52+
"kmp_search",
53+
"knapsack_01",
54+
"kruskal_mst",
55+
"longest_common_subsequence",
56+
"manacher_longest_palindrome",
57+
"merge_sort",
58+
"prim_mst",
59+
"quick_select",
60+
"rabin_karp_search",
61+
"reservoir_sample",
62+
"sieve_of_eratosthenes",
63+
"sliding_window_maximum",
64+
"tarjan_strongly_connected_components",
65+
"topological_sort",
66+
"two_sum",
67+
]

dsa_programs/bellman_ford.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""Bellman-Ford shortest paths with negative cycle detection."""
2+
3+
from typing import Dict, Iterable, List, Set, Tuple, TypeVar
4+
5+
T = TypeVar("T")
6+
Edge = Tuple[T, T, float]
7+
8+
9+
def bellman_ford(vertices: Iterable[T], edges: Iterable[Edge], source: T) -> Dict[T, float]:
10+
edge_list: List[Edge] = list(edges)
11+
vertex_set: Set[T] = set(vertices)
12+
for u, v, _ in edge_list:
13+
vertex_set.add(u)
14+
vertex_set.add(v)
15+
vertex_set.add(source)
16+
distances: Dict[T, float] = {vertex: float("inf") for vertex in vertex_set}
17+
distances[source] = 0.0
18+
for _ in range(len(vertex_set) - 1):
19+
updated = False
20+
for u, v, weight in edge_list:
21+
if distances[u] + weight < distances[v]:
22+
distances[v] = distances[u] + weight
23+
updated = True
24+
if not updated:
25+
break
26+
for u, v, weight in edge_list:
27+
if distances[u] + weight < distances[v]:
28+
raise ValueError("Graph contains a negative-weight cycle")
29+
return distances

dsa_programs/binary_search.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
"""Iterative binary search on a sorted sequence."""
2+
3+
from typing import Sequence
4+
5+
6+
def binary_search(items: Sequence[int], target: int) -> int:
7+
left, right = 0, len(items) - 1
8+
while left <= right:
9+
mid = (left + right) // 2
10+
value = items[mid]
11+
if value == target:
12+
return mid
13+
if value < target:
14+
left = mid + 1
15+
else:
16+
right = mid - 1
17+
return -1
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"""Boyer-Moore majority vote algorithm."""
2+
3+
from typing import Iterable, List, TypeVar
4+
5+
T = TypeVar("T")
6+
7+
8+
def boyer_moore_majority(items: Iterable[T]) -> T:
9+
data: List[T] = list(items)
10+
if not data:
11+
raise ValueError("Sequence is empty")
12+
candidate: T | None = None
13+
count = 0
14+
for value in data:
15+
if count == 0:
16+
candidate = value
17+
count = 1
18+
elif value == candidate:
19+
count += 1
20+
else:
21+
count -= 1
22+
assert candidate is not None # mypy helper
23+
if data.count(candidate) <= len(data) // 2:
24+
raise ValueError("No majority element present")
25+
return candidate
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
"""Breadth-first search returning discovery order from a starting node."""
2+
3+
from collections import deque
4+
from typing import Deque, Dict, Iterable, List, Set, TypeVar
5+
6+
T = TypeVar("T")
7+
8+
9+
def breadth_first_search(graph: Dict[T, Iterable[T]], start: T) -> List[T]:
10+
visited: Set[T] = set()
11+
order: List[T] = []
12+
queue: Deque[T] = deque([start])
13+
visited.add(start)
14+
while queue:
15+
node = queue.popleft()
16+
order.append(node)
17+
for neighbor in graph.get(node, ()): # gracefully handle missing keys
18+
if neighbor not in visited:
19+
visited.add(neighbor)
20+
queue.append(neighbor)
21+
return order

dsa_programs/depth_first_search.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
"""Depth-first search using recursion to record visitation order."""
2+
3+
from typing import Dict, Iterable, List, Set, TypeVar
4+
5+
T = TypeVar("T")
6+
7+
8+
def depth_first_search(graph: Dict[T, Iterable[T]], start: T) -> List[T]:
9+
visited: Set[T] = set()
10+
order: List[T] = []
11+
12+
def _dfs(node: T) -> None:
13+
visited.add(node)
14+
order.append(node)
15+
for neighbor in graph.get(node, ()): # support sparse adjacency
16+
if neighbor not in visited:
17+
_dfs(neighbor)
18+
19+
_dfs(start)
20+
return order
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
"""Dijkstra's shortest path algorithm with a min-heap."""
2+
3+
from heapq import heappop, heappush
4+
from typing import Dict, Iterable, List, Tuple, TypeVar
5+
6+
T = TypeVar("T")
7+
8+
Graph = Dict[T, Iterable[Tuple[T, float]]]
9+
10+
11+
def dijkstra_shortest_path(graph: Graph, source: T) -> Dict[T, float]:
12+
distances: Dict[T, float] = {source: 0.0}
13+
heap: List[Tuple[float, T]] = [(0.0, source)]
14+
while heap:
15+
current_dist, node = heappop(heap)
16+
if current_dist > distances.get(node, float("inf")):
17+
continue
18+
for neighbor, weight in graph.get(node, ()): # missing key means no outgoing edges
19+
cost = current_dist + weight
20+
if cost < distances.get(neighbor, float("inf")):
21+
distances[neighbor] = cost
22+
heappush(heap, (cost, neighbor))
23+
return distances
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
"""In-place Dutch national flag partitioning for values 0, 1, and 2."""
2+
3+
from typing import MutableSequence
4+
5+
6+
def dutch_national_flag(items: MutableSequence[int]) -> None:
7+
low = mid = 0
8+
high = len(items) - 1
9+
while mid <= high:
10+
value = items[mid]
11+
if value == 0:
12+
items[low], items[mid] = items[mid], items[low]
13+
low += 1
14+
mid += 1
15+
elif value == 1:
16+
mid += 1
17+
elif value == 2:
18+
items[mid], items[high] = items[high], items[mid]
19+
high -= 1
20+
else:
21+
raise ValueError("Items must be 0, 1, or 2 only")

dsa_programs/edit_distance.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
"""Levenshtein edit distance via dynamic programming."""
2+
3+
from typing import Sequence
4+
5+
6+
def edit_distance(a: Sequence[str], b: Sequence[str]) -> int:
7+
if isinstance(a, str):
8+
seq_a = list(a)
9+
else:
10+
seq_a = list(a)
11+
if isinstance(b, str):
12+
seq_b = list(b)
13+
else:
14+
seq_b = list(b)
15+
m = len(seq_a)
16+
n = len(seq_b)
17+
dp = [[0] * (n + 1) for _ in range(m + 1)]
18+
for i in range(m + 1):
19+
dp[i][0] = i
20+
for j in range(n + 1):
21+
dp[0][j] = j
22+
for i in range(1, m + 1):
23+
for j in range(1, n + 1):
24+
cost = 0 if seq_a[i - 1] == seq_b[j - 1] else 1
25+
dp[i][j] = min(
26+
dp[i - 1][j] + 1,
27+
dp[i][j - 1] + 1,
28+
dp[i - 1][j - 1] + cost,
29+
)
30+
return dp[m][n]

0 commit comments

Comments
 (0)