diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 00000000..bf5d9e3e --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,20 @@ +name: Rust CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build-ubuntu-rustc: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: install rustc + run: | + sudo apt install rustc + - name: compile + run: | + cd rust + cargo diff --git a/README.md b/README.md index 0f48bd6f..81db93e9 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![C++ CI](https://github.com/indy256/codelibrary/workflows/C++%20CI/badge.svg)](https://github.com/indy256/codelibrary/actions?query=workflow%3A%22C%2B%2B+CI%22) [![License](https://img.shields.io/badge/license-UNLICENSE-green.svg)](https://github.com/indy256/codelibrary/blob/master/UNLICENSE) -### Collection of algorithms and data structures in C++, Java, Kotlin and Python +### Collection of algorithms and data structures in C++, Java, Kotlin, Python and Rust #### Data structures + [x] Segment tree [**c++**](cpp/structures/segment_tree.h) [**java**](java/structures/SegmentTree.java) [**kotlin**](kotlin/SegmentTree.kt) diff --git a/rust/.gitignore b/rust/.gitignore new file mode 100644 index 00000000..17595cfa --- /dev/null +++ b/rust/.gitignore @@ -0,0 +1,4 @@ +.idea +*.iml +Cargo.lock +target diff --git a/rust/Cargo.toml b/rust/Cargo.toml new file mode 100644 index 00000000..2953b0d9 --- /dev/null +++ b/rust/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "codelibrary" +version = "0.1.0" + +edition = "2018" + +[[bin]] +name = "topological_sort" +path = "graphs/dfs/topological_sort.rs" + +[[bin]] +name = "dijkstra" +path = "graphs/shortestpaths/dijkstra.rs" + +[[bin]] +name = "max_bipartite_matching_EV" +path = "graphs/matchings/max_bipartite_matching_EV.rs" + +[[bin]] +name = "euclid" +path = "numbertheory/euclid.rs" + +[[bin]] +name = "disjoint_sets" +path = "structures/disjoint_sets.rs" + +[[bin]] +name = "fenwick_tree" +path = "structures/fenwick_tree.rs" diff --git a/rust/graphs/dfs/topological_sort.rs b/rust/graphs/dfs/topological_sort.rs new file mode 100644 index 00000000..0e9f7775 --- /dev/null +++ b/rust/graphs/dfs/topological_sort.rs @@ -0,0 +1,28 @@ +fn dfs(graph: &Vec>, used: &mut Vec, order: &mut Vec, u: usize) { + used[u] = true; + for v in &graph[u] { + if !used[*v] { + dfs(graph, used, order, *v); + } + } + order.push(u); +} + +pub fn topological_sort(graph: &Vec>) -> Vec { + let n = graph.len(); + let mut used = vec![false; n]; + let mut order = Vec::::new(); + for i in 0..n { + if !used[i] { + dfs(graph, &mut used, &mut order, i); + } + } + order.reverse(); + return order; +} + +fn main() { + let g = vec![vec![0], vec![], vec![0, 1]]; + let order = topological_sort(&g); + assert_eq!(order, vec![2, 1, 0]); +} diff --git a/rust/graphs/matchings/max_bipartite_matching_EV.rs b/rust/graphs/matchings/max_bipartite_matching_EV.rs new file mode 100644 index 00000000..ba3db963 --- /dev/null +++ b/rust/graphs/matchings/max_bipartite_matching_EV.rs @@ -0,0 +1,31 @@ +fn find_path(graph: &Vec>, u1: usize, matching: &mut Vec, vis: &mut Vec) -> bool { + vis[u1] = true; + for v in &graph[u1] { + let u2 = matching[*v]; + if u2 == usize::MAX || (!vis[u2] && find_path(graph, u2, matching, vis)) { + matching[*v] = u1; + return true; + } + } + return false; +} + +pub fn max_matching(graph: &Vec>, n2: usize) -> (usize, Vec) { + let n1 = graph.len(); + let mut matching = vec![usize::MAX; n2]; + let mut matches = 0; + for u in 0..n1 { + let mut vis = vec![false; n1]; + if find_path(graph, u, &mut matching, &mut vis) { + matches += 1; + } + } + return (matches, matching); +} + +fn main() { + let g = vec![vec![0, 1], vec![0]]; + let (cardinality, matching) = max_matching(&g, 2); + assert_eq!(cardinality, 2); + assert_eq!(matching, vec![1, 0]); +} diff --git a/rust/graphs/shortestpaths/dijkstra.rs b/rust/graphs/shortestpaths/dijkstra.rs new file mode 100644 index 00000000..b02d6325 --- /dev/null +++ b/rust/graphs/shortestpaths/dijkstra.rs @@ -0,0 +1,31 @@ +use std::collections::BinaryHeap; + +// https://cp-algorithms.com/graph/dijkstra_sparse.html +// O(E*log(V)) time and O(E) memory +pub fn dijkstra_heap(graph: &Vec>, s: usize) -> (Vec, Vec) { + let n = graph.len(); + let mut prio = vec![i32::MAX; n]; + let mut pred = vec![usize::MAX; n]; + let mut q = BinaryHeap::<(i32, usize)>::new(); + prio[s] = 0; + q.push((0, s)); + while let Some((d, u)) = q.pop() { + if -d != prio[u] { continue; } + for (v, len) in &graph[u] { + let nprio = prio[u] + len; + if prio[*v] > nprio { + prio[*v] = nprio; + pred[*v] = u; + q.push((-nprio, *v)); + } + } + } + return (prio, pred); +} + +fn main() { + let g = vec![vec![(1, 10), (2, 8)], vec![(2, -5)], vec![]]; + let (prio, pred) = dijkstra_heap(&g, 0); + assert_eq!(prio, vec![0, 10, 5]); + assert_eq!(pred, vec![usize::MAX, 0, 1]); +} diff --git a/rust/numbertheory/euclid.rs b/rust/numbertheory/euclid.rs new file mode 100644 index 00000000..314caf20 --- /dev/null +++ b/rust/numbertheory/euclid.rs @@ -0,0 +1,30 @@ +fn gcd(a: i32, b: i32) -> i32 { + return if b == 0 { a.abs() } else { gcd(b, a % b) }; +} + +// returns { gcd(a,b), x, y } such that gcd(a,b) = a*x + b*y +fn euclid(mut a: i64, mut b: i64) -> [i64; 3] { + let mut x: i64 = 1; + let mut y: i64 = 0; + let mut x1: i64 = 0; + let mut y1: i64 = 1; + // invariant: a=a_orig*x+b_orig*y, b=a_orig*x1+b_orig*y1 + while b != 0 { + let q = a / b; + let _x1 = x1; + let _y1 = y1; + let _b = b; + x1 = x - q * x1; + y1 = y - q * y1; + b = a - q * b; + x = _x1; + y = _y1; + a = _b; + } + return if a > 0 { [a, x, y] } else { [-a, -x, -y] }; +} + +fn main() { + assert_eq!(gcd(15, 20), 5); + assert_eq!(euclid(6, 9), [3, -1, 1]); +} diff --git a/rust/structures/disjoint_sets.rs b/rust/structures/disjoint_sets.rs new file mode 100644 index 00000000..221ba7a9 --- /dev/null +++ b/rust/structures/disjoint_sets.rs @@ -0,0 +1,30 @@ +struct DisjointSets { + p: Vec +} + +impl DisjointSets { + pub fn new(n: usize) -> Self { + DisjointSets { p: (0..n).collect() } + } + + pub fn root(&mut self, x: usize) -> usize { + if x != self.p[x] { + self.p[x] = self.root(self.p[x]); + } + self.p[x] + } + + pub fn unite(&mut self, a: usize, b: usize) { + let a = self.root(a); + let b = self.root(b); + self.p[b] = a; + } +} + +fn main() { + let mut ds = DisjointSets::new(3); + ds.unite(0, 2); + assert_eq!(ds.root(0), 0); + assert_eq!(ds.root(1), 1); + assert_eq!(ds.root(2), 0); +} diff --git a/rust/structures/fenwick_tree.rs b/rust/structures/fenwick_tree.rs new file mode 100644 index 00000000..ba84a0a5 --- /dev/null +++ b/rust/structures/fenwick_tree.rs @@ -0,0 +1,38 @@ +use std::ops::AddAssign; + +struct Fenwick { + t: Vec +} + +impl> Fenwick { + fn new(n: usize) -> Self { + Fenwick { t: vec![0.into(); n] } + } + + pub fn add(&mut self, mut i: usize, value: T) { + while i < self.t.len() { + self.t[i] += value; + i |= i + 1; + } + } + + // sum[0..i] + pub fn sum(&self, mut i: i32) -> T { + let mut res: T = 0.into(); + while i >= 0 { + res += self.t[i as usize]; + i = (i & (i + 1)) - 1; + } + return res; + } +} + +fn main() { + let mut t = Fenwick::::new(3); + t.add(0, 4); + t.add(1, 5); + t.add(2, 5); + t.add(2, 5); + assert_eq!(t.sum(0), 4); + assert_eq!(t.sum(2), 19); +}