Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ license = "GPL-3.0"
repository = "https://github.com/tekawade/algs4-rust"
keywords = ["algorithms", "data-structures", "education"]
categories = ["algorithms", "data-structures"]
rust-version = "1.82.0"

[workspace.dependencies]
# Common dependencies shared across modules
Expand Down
37 changes: 23 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -517,20 +517,29 @@ cargo test --doc
```

### Benchmarking

```bash
# Run graph benchmarks
cargo bench -p algs4-graphs

# Benchmarks include:
# - Graph creation
# - DFS/BFS traversal
# - Connected components
# - Dijkstra shortest paths
# - Minimum spanning trees
# - Topological sort
# - Strongly connected components
```

```bash
# Run benchmarks for specific module
cargo bench -p algs4-fundamentals
cargo bench -p algs4-sorting
cargo bench -p algs4-searching
cargo bench -p algs4-graphs
cargo bench -p algs4-strings
cargo bench -p algs4-geometry
cargo bench -p algs4-advanced

# Run all benchmarks (may take a while)
cargo bench --workspace

# Benchmarks include:
# - Fundamentals: Bags, Queues, Stacks, Union-Find
# - Sorting: All major sorting algorithms (Elementary, Merge, Quick, Heap, String Sorts)
# - Searching: BST, Red-Black BST, Hash Tables, Tries
# - Graphs: Traversal, Shortest Paths, MST, etc.
# - Strings: Pattern Matching (KMP), Tries
# - Geometry: Convex Hull
# - Advanced: Fenwick Tree, B-Tree
```

### Documentation

Expand Down
6 changes: 6 additions & 0 deletions modules/advanced/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,9 @@ algs4-searching = { version = "0.1.0", path = "../searching" }
algs4-graphs = { version = "0.1.0", path = "../graphs" }

[dev-dependencies]
criterion = "0.5"
rand = "0.8"

[[bench]]
name = "advanced_benchmarks"
harness = false
30 changes: 30 additions & 0 deletions modules/advanced/benches/advanced_benchmarks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use algs4_advanced::fenwick_tree::FenwickTree;
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
use rand::prelude::SliceRandom;
use rand::thread_rng;

fn advanced_benchmark(c: &mut Criterion) {
let mut group = c.benchmark_group("advanced");

for size in [1000, 5000].iter() {
let mut rng = thread_rng();
let mut data: Vec<i32> = (0..*size as i32).collect();
data.shuffle(&mut rng);
Comment on lines +10 to +12

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The rng and data variables are created but never used within the benchmark loop. This dead code should be removed to improve clarity.

Comment on lines +10 to +12

Copilot AI Nov 19, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variables rng and data are created outside the benchmark closure but never used. These should be removed as they don't contribute to the benchmark and may confuse readers about what is being measured.

Suggested change
let mut rng = thread_rng();
let mut data: Vec<i32> = (0..*size as i32).collect();
data.shuffle(&mut rng);

Copilot uses AI. Check for mistakes.

group.bench_with_input(
BenchmarkId::new("fenwick_tree_sum", size),
size,
|b, &size| {
b.iter(|| {
let data = vec![1; size];
let ft = FenwickTree::new(black_box(data));
ft.rsq(size - 1)
});
},
);
}
group.finish();
}

criterion_group!(benches, advanced_benchmark);
criterion_main!(benches);
6 changes: 6 additions & 0 deletions modules/fundamentals/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,9 @@ lazy_static = "1.5"
byteorder = { workspace = true }

[dev-dependencies]
criterion = "0.5"
rand = "0.8"

[[bench]]
name = "fundamentals_benchmarks"
harness = false
174 changes: 174 additions & 0 deletions modules/fundamentals/benches/fundamentals_benchmarks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
use algs4_fundamentals::collections::linked_bag::LinkedBag;
use algs4_fundamentals::collections::linked_queue::LinkedQueue;
use algs4_fundamentals::collections::linked_stack::LinkedStack;
use algs4_fundamentals::collections::resizing_array_bag::ResizingArrayBag;
use algs4_fundamentals::collections::resizing_array_queue::ResizingArrayQueue;
use algs4_fundamentals::collections::resizing_array_stack::ResizingArrayStack;
use algs4_fundamentals::union_find::quick_find_uf::QuickFindUF;
use algs4_fundamentals::union_find::quick_union_uf::QuickUnionUF;
use algs4_fundamentals::union_find::weighted_quick_union_uf::WeightedQuickUnionUF;
use algs4_fundamentals::union_find::weighted_quick_union_uf::WeightedQuickUnionUF as UF; // UF trait might not be public or exist as named

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The alias UF is imported but never used. This line can be removed to avoid confusion.

Copilot AI Nov 19, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The import alias UF is defined but never used in the code. Remove this unused import to clean up the code.

Suggested change
use algs4_fundamentals::union_find::weighted_quick_union_uf::WeightedQuickUnionUF as UF; // UF trait might not be public or exist as named

Copilot uses AI. Check for mistakes.
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};

fn bag_benchmark(c: &mut Criterion) {
let mut group = c.benchmark_group("bag");

for size in [1000, 10000].iter() {
group.bench_with_input(
BenchmarkId::new("linked_bag_add", size),
size,
|b, &size| {
b.iter(|| {
let mut bag = LinkedBag::new();
for i in 0..size {
bag.add(black_box(i));
}
});
},
);

group.bench_with_input(
BenchmarkId::new("resizing_array_bag_add", size),
size,
|b, &size| {
b.iter(|| {
let mut bag = ResizingArrayBag::new();
for i in 0..size {
bag.add(black_box(i));
}
});
},
);
}
group.finish();
}

fn queue_benchmark(c: &mut Criterion) {
let mut group = c.benchmark_group("queue");

for size in [1000, 10000].iter() {
group.bench_with_input(
BenchmarkId::new("linked_queue_enqueue_dequeue", size),
size,
|b, &size| {
b.iter(|| {
let mut queue = LinkedQueue::new();
for i in 0..size {
queue.enqueue(black_box(i));
}
for _ in 0..size {
queue.dequeue();
}
});
},
);

group.bench_with_input(
BenchmarkId::new("resizing_array_queue_enqueue_dequeue", size),
size,
|b, &size| {
b.iter(|| {
let mut queue = ResizingArrayQueue::new();
for i in 0..size {
queue.enqueue(black_box(i));
}
for _ in 0..size {
queue.dequeue();
}
});
},
);
}
group.finish();
}

fn stack_benchmark(c: &mut Criterion) {
let mut group = c.benchmark_group("stack");

for size in [1000, 10000].iter() {
group.bench_with_input(
BenchmarkId::new("linked_stack_push_pop", size),
size,
|b, &size| {
b.iter(|| {
let mut stack = LinkedStack::new();
for i in 0..size {
stack.push(black_box(i));
}
for _ in 0..size {
stack.pop();
}
});
},
);

group.bench_with_input(
BenchmarkId::new("resizing_array_stack_push_pop", size),
size,
|b, &size| {
b.iter(|| {
let mut stack = ResizingArrayStack::new();
for i in 0..size {
stack.push(black_box(i));
}
for _ in 0..size {
stack.pop();
}
});
},
);
}
group.finish();
}

fn union_find_benchmark(c: &mut Criterion) {
let mut group = c.benchmark_group("union_find");

for size in [1000, 5000].iter() {
let ops = size * 2;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The ops variable is assigned but never used. It should be removed.

Copilot AI Nov 19, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable ops is defined but never used. Remove this unused variable.

Suggested change
let ops = size * 2;

Copilot uses AI. Check for mistakes.

group.bench_with_input(BenchmarkId::new("quick_find", size), size, |b, &size| {
b.iter(|| {
let mut uf = QuickFindUF::new(black_box(size));
for i in 0..size - 1 {
uf.union(i, i + 1);
}
uf.connected(0, size - 1)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The result of uf.connected is not used, so the call might be optimized away by the compiler. Wrap it in black_box to ensure the benchmark is accurate. This applies to the other union_find benchmarks as well.

Suggested change
uf.connected(0, size - 1)
black_box(uf.connected(0, size - 1))

});
});

group.bench_with_input(BenchmarkId::new("quick_union", size), size, |b, &size| {
b.iter(|| {
let mut uf = QuickUnionUF::new(black_box(size));
for i in 0..size - 1 {
uf.union(i, i + 1);
}
uf.connected(0, size - 1)
});
});

group.bench_with_input(
BenchmarkId::new("weighted_quick_union", size),
size,
|b, &size| {
b.iter(|| {
let mut uf = WeightedQuickUnionUF::new(black_box(size));
for i in 0..size - 1 {
uf.union(i, i + 1);
}
uf.connected(0, size - 1)
});
},
);
}
group.finish();
}

criterion_group!(
benches,
bag_benchmark,
queue_benchmark,
stack_benchmark,
union_find_benchmark
);
criterion_main!(benches);
12 changes: 6 additions & 6 deletions modules/fundamentals/src/collections/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@
//! **Reference:** <https://algs4.cs.princeton.edu/13stacks>

// Linked implementations
mod linked_bag;
mod linked_queue;
mod linked_stack;
pub mod linked_bag;
pub mod linked_queue;
pub mod linked_stack;

pub use linked_bag::LinkedBag;
pub use linked_queue::LinkedQueue;
pub use linked_stack::LinkedStack;

// Array implementations
mod resizing_array_bag;
mod resizing_array_queue;
mod resizing_array_stack;
pub mod resizing_array_bag;
pub mod resizing_array_queue;
pub mod resizing_array_stack;

pub use resizing_array_bag::ResizingArrayBag;
pub use resizing_array_queue::ResizingArrayQueue;
Expand Down
6 changes: 3 additions & 3 deletions modules/fundamentals/src/union_find/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@
//!
//! **Reference:** <https://algs4.cs.princeton.edu/15uf>

mod quick_find_uf;
mod quick_union_uf;
mod weighted_quick_union_uf;
pub mod quick_find_uf;
pub mod quick_union_uf;
pub mod weighted_quick_union_uf;

pub use quick_find_uf::QuickFindUF;
pub use quick_union_uf::QuickUnionUF;
Expand Down
6 changes: 6 additions & 0 deletions modules/geometry/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,9 @@ description = "Geometric algorithms from Algorithms 4th Edition"
algs4-fundamentals = { version = "0.1.0", path = "../fundamentals" }

[dev-dependencies]
criterion = "0.5"
rand = "0.8"

[[bench]]
name = "geometry_benchmarks"
harness = false
26 changes: 26 additions & 0 deletions modules/geometry/benches/geometry_benchmarks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use algs4_geometry::graham_scan::GrahamScan;
use algs4_geometry::point2d::Point2D;
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
use rand::{thread_rng, Rng};

fn geometry_benchmark(c: &mut Criterion) {
let mut group = c.benchmark_group("geometry");

for size in [1000, 5000].iter() {
let mut rng = thread_rng();
let points: Vec<Point2D> = (0..*size)
.map(|_| Point2D::new(rng.gen_range(0.0..100.0), rng.gen_range(0.0..100.0)))
.collect();

group.bench_with_input(BenchmarkId::new("graham_scan", size), &points, |b, pts| {
b.iter(|| {
let mut p = pts.clone();
GrahamScan::new(black_box(&mut p));
Comment on lines +17 to +18

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The p vector does not need to be mutable. More importantly, the result of GrahamScan::new is not used and could be optimized away by the compiler. You should wrap the function call in black_box to ensure the benchmark is accurate.

Suggested change
let mut p = pts.clone();
GrahamScan::new(black_box(&mut p));
let p = pts.clone();
black_box(GrahamScan::new(&p));

});
});
}
group.finish();
}

criterion_group!(benches, geometry_benchmark);
criterion_main!(benches);
6 changes: 6 additions & 0 deletions modules/searching/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,9 @@ description = "Searching algorithms and symbol tables from Algorithms 4th Editio
algs4-fundamentals = { version = "0.1.0", path = "../fundamentals" }

[dev-dependencies]
criterion = "0.5"
rand = "0.8"

[[bench]]
name = "searching_benchmarks"
harness = false
Loading
Loading