From c24c34ffcc8aa19b9b366e3bf6d8ed3a363f85e7 Mon Sep 17 00:00:00 2001 From: Sudip Date: Sat, 17 Jan 2026 16:46:38 +0000 Subject: [PATCH 1/5] feat: add documentation for dfs algorithm --- README.md | 13 +++-- crates/dsa/Cargo.toml | 4 ++ crates/dsa/src/algorithms/greedy/dfs.rs | 64 +++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 crates/dsa/src/algorithms/greedy/dfs.rs diff --git a/README.md b/README.md index b7632a1..0528640 100644 --- a/README.md +++ b/README.md @@ -129,8 +129,8 @@ cargo test --bin huffman cargo run --bin binary_search ``` -3. [Depth First Search (DFS)] -4. [Breadth First Search (BFS)] +3. [Jump Search] +4. [Interpolation Search] #### [1.2.2. Sorting](crates/dsa/src/algorithms/sorting/) @@ -188,7 +188,14 @@ cargo test --bin huffman 6. [Bellman-Ford Algorithm] 7. [Floyd-Warshall Algorithm] 8. [Topological Sort] -9. [A* Search Algorithm] +9. [Depth First Search (DFS)](crates/dsa/src/algorithms/greedy/dfs.rs) + + ```sh + cargo run --bin dfs + ``` + +10. [Breadth First Search (BFS)] +11. [A* Search Algorithm] #### [1.2.4. Miscellaneous Algorithms](crates/dsa/src/algorithms/misc/) diff --git a/crates/dsa/Cargo.toml b/crates/dsa/Cargo.toml index 41b6844..ba262a0 100644 --- a/crates/dsa/Cargo.toml +++ b/crates/dsa/Cargo.toml @@ -84,6 +84,10 @@ path = "src/algorithms/greedy/huffman_coding.rs" name = "kruskal" path = "src/algorithms/greedy/kruskal.rs" +[[bin]] +name = "dfs" +path = "src/algorithms/greedy/dfs.rs" + # Miscellaneous [[bin]] diff --git a/crates/dsa/src/algorithms/greedy/dfs.rs b/crates/dsa/src/algorithms/greedy/dfs.rs new file mode 100644 index 0000000..4f5d695 --- /dev/null +++ b/crates/dsa/src/algorithms/greedy/dfs.rs @@ -0,0 +1,64 @@ +//! # Depth First Search Algorithm +//! +//! Depth first search algorithm is a graph searching algorithm that starts at +//! the root node and explores as far as possible to find out whether the node +//! exists in the tree. +//! +//! +//! some example of DFS implementation are as follows: +//! +//! 1. dependency resolution +//! 2. topological sorting +//! 3. maze generation, etc. +//! +//! +//! References: +//! +//! +//! +//! +//! +//! The following example shows the dependency resolution using DFS. +//! In this example, a Package will behave as a Node, and its dependencies will +//! behave as its children nodes. +//! +//! example: +//! +//! app -> [web, auth] +//! web -> [http, logger, db] +//! auth -> [crypto, db] +//! db -> [os] +//! crypto -> [os] +//! logger -> [os] +//! os -> [] +//! ... +//! +//! +//! Which will look something like this +//! ```text +//! App +//! / \ +//! / \ +//! web auth +//! / \ \ | \ +//! http logger db crypto +//! \ | / / +//! \ | / / +//! OS +//! ... +//! +//! ``` + +struct Package { + id: String, + dependencies: Vec, +} + +struct DependencyGraph { + packages: Package, +} + +fn main() { + // + println!("Depth first search algorithm") +} From 1e7a361d41ea878022b3fd1caff6ecce5934c2d0 Mon Sep 17 00:00:00 2001 From: Sudip Date: Sat, 17 Jan 2026 18:08:36 +0000 Subject: [PATCH 2/5] feat: add package and registry implementation --- crates/dsa/src/algorithms/greedy/dfs.rs | 119 +++++++++++++++++++++++- 1 file changed, 114 insertions(+), 5 deletions(-) diff --git a/crates/dsa/src/algorithms/greedy/dfs.rs b/crates/dsa/src/algorithms/greedy/dfs.rs index 4f5d695..de3a349 100644 --- a/crates/dsa/src/algorithms/greedy/dfs.rs +++ b/crates/dsa/src/algorithms/greedy/dfs.rs @@ -49,16 +49,125 @@ //! //! ``` +use std::collections::{HashMap, HashSet}; + +#[derive(Clone, Debug)] struct Package { id: String, - dependencies: Vec, + deps: Vec, // dependencies +} + +#[derive(Debug)] +struct Registry { + packages: HashMap, } -struct DependencyGraph { - packages: Package, +impl Package { + fn new(id: String, deps: Vec) -> Self { + Self { id, deps } + } +} + +impl Registry { + fn new() -> Self { + Self { + packages: HashMap::new(), + } + } + fn insert(&mut self, pkg: Package) { + self.packages.insert(pkg.id.clone(), pkg); + } + + fn depth_first_search( + &self, + id: String, + visiting: &mut HashSet, + resolved: &mut HashSet, + output: &mut Vec, + ) -> Result<(), String> { + if resolved.contains(&id) { + return Ok(()); + } + + // if a depends on b, and b depends on a, then we have a circular dependency + if visiting.contains(&id) { + return Err(format!("circular dependency detected at package {}", id)); + } + + visiting.insert(id.clone()); + + let pkg = self + .packages + .get(&id) + .ok_or_else(|| format!("package {} not found in registry", id))?; + + for dep in &pkg.deps { + self.depth_first_search(dep.clone(), visiting, resolved, output)?; + } + + visiting.remove(&id); + resolved.insert(id.clone()); + output.push(id); + + Ok(()) + } + + fn resolve(&self, id: String) -> Result, String> { + // resolve packages + let mut visiting = HashSet::new(); + let mut resolved = HashSet::new(); + let mut output = Vec::new(); + self.depth_first_search(id, &mut visiting, &mut resolved, &mut output)?; + + Ok(output) + } + + fn install(&self, id: String) -> Result<(), String> { + println!("{}", "-".repeat(40)); + let deps = self.resolve(id.clone())?; + println!("Installing package \"{}\"", id); + println!("Dependencies: {:?}", deps); + Ok(()) + } } fn main() { - // - println!("Depth first search algorithm") + println!("Depth first search algorithm"); + + let mut registry = Registry::new(); + + // build a graph of packages and their dependencies (similar to a lockfile) + registry.insert(Package::new("os".to_owned(), vec![])); + registry.insert(Package::new("http".to_owned(), vec!["os".to_owned()])); + registry.insert(Package::new("crypto".to_owned(), vec!["os".to_owned()])); + registry.insert(Package::new("db".to_owned(), vec!["os".to_owned()])); + registry.insert(Package::new("logger".to_owned(), vec!["os".to_owned()])); + + // install higher level packages which will resolve the dependencies before installing + let web = Package::new( + "web".to_owned(), + vec!["http".to_owned(), "logger".to_owned()], + ); + + let auth = Package::new( + "auth".to_owned(), + vec!["db".to_owned(), "crypto".to_owned()], + ); + registry.insert(web); + registry.insert(auth); + + // insert app package which depends on web and auth + registry.insert(Package::new( + "app".to_owned(), + vec!["web".to_owned(), "auth".to_owned()], + )); + + // resolve dependencies for "auth" package + for apps in ["web", "auth", "app"] { + if let Ok(()) = registry.install(apps.to_owned()) { + println!("Package '{}' installed successfully", apps); + } else { + println!("Failed to install package '{}'", apps); + } + } } From 8af106bd2a7ea1eca58b0d85e250e54358c25b5d Mon Sep 17 00:00:00 2001 From: Sudip Date: Sat, 17 Jan 2026 18:41:59 +0000 Subject: [PATCH 3/5] feat: add install cache for already installed apps --- crates/dsa/src/algorithms/greedy/dfs.rs | 41 ++++++++++++++----------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/crates/dsa/src/algorithms/greedy/dfs.rs b/crates/dsa/src/algorithms/greedy/dfs.rs index de3a349..ca4d1bf 100644 --- a/crates/dsa/src/algorithms/greedy/dfs.rs +++ b/crates/dsa/src/algorithms/greedy/dfs.rs @@ -59,6 +59,7 @@ struct Package { #[derive(Debug)] struct Registry { + installed: HashSet, packages: HashMap, } @@ -71,6 +72,7 @@ impl Package { impl Registry { fn new() -> Self { Self { + installed: HashSet::new(), packages: HashMap::new(), } } @@ -122,11 +124,23 @@ impl Registry { Ok(output) } - fn install(&self, id: String) -> Result<(), String> { + fn install(&mut self, id: String) -> Result<(), String> { println!("{}", "-".repeat(40)); + if self.installed.contains(&id) { + println!("Package \"{}\" is already installed", id); + return Ok(()); + } else { + println!("Installing package \"{}\"", id); + } let deps = self.resolve(id.clone())?; - println!("Installing package \"{}\"", id); - println!("Dependencies: {:?}", deps); + println!("DFS Graph: {:?}", deps); + + // install sub dependencies first, and ignore self dependency from dfs + for dep in deps.iter().filter(|&dep| dep != &id) { + self.install(dep.to_owned())? + } + self.installed.insert(id.clone()); + println!("Package \"{}\" installed successfully", id); Ok(()) } } @@ -144,17 +158,14 @@ fn main() { registry.insert(Package::new("logger".to_owned(), vec!["os".to_owned()])); // install higher level packages which will resolve the dependencies before installing - let web = Package::new( + registry.insert(Package::new( "web".to_owned(), vec!["http".to_owned(), "logger".to_owned()], - ); - - let auth = Package::new( + )); + registry.insert(Package::new( "auth".to_owned(), vec!["db".to_owned(), "crypto".to_owned()], - ); - registry.insert(web); - registry.insert(auth); + )); // insert app package which depends on web and auth registry.insert(Package::new( @@ -162,12 +173,6 @@ fn main() { vec!["web".to_owned(), "auth".to_owned()], )); - // resolve dependencies for "auth" package - for apps in ["web", "auth", "app"] { - if let Ok(()) = registry.install(apps.to_owned()) { - println!("Package '{}' installed successfully", apps); - } else { - println!("Failed to install package '{}'", apps); - } - } + // install package app + registry.install("app".to_owned()).unwrap(); } From fe723ad915df04d0ea4eb5d0b638cff564d79422 Mon Sep 17 00:00:00 2001 From: Sudip Date: Sat, 17 Jan 2026 18:43:37 +0000 Subject: [PATCH 4/5] feat: update readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0528640..7e1139c 100644 --- a/README.md +++ b/README.md @@ -190,6 +190,8 @@ cargo test --bin huffman 8. [Topological Sort] 9. [Depth First Search (DFS)](crates/dsa/src/algorithms/greedy/dfs.rs) + An example of a package manager to resolve and install dependencies using DFS approach. + ```sh cargo run --bin dfs ``` From 6dadf1565997e7f57d6d21c955683ec86fccb2db Mon Sep 17 00:00:00 2001 From: Sudip Date: Sat, 17 Jan 2026 18:46:56 +0000 Subject: [PATCH 5/5] Update Pull Request example --- .github/PULL_REQUEST_TEMPLATE.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index d674a82..b6a9e90 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -15,10 +15,8 @@ ## TARGET -- [ ] Data Structure -- [ ] Algorithm +- [ ] DSA - [ ] Design Pattern - [ ] Problem Solving -- [ ] Complexity Analysis - [ ] Advanced Concept - [ ] Project