Skip to content

Repository files navigation

The Grand Algorithms Project

CI

Docs site: leon-lourenco.github.io/algorithms-project — every algorithm with a diagram, both examples, and its coverage report, browsable in English/Português/Español.

Read this in: English | Português | Español

A modular Java project covering the classic algorithms taught across a university CS curriculum — sorting, searching, dynamic programming, greedy strategies, string matching, number theory, and backtracking. One Gradle module per algorithm, each with its own README, a from-scratch implementation, a second implementation applying that algorithm to a real scenario, and a JMH microbenchmark that turns the textbook Big-O claim into a measured, reproducible number. Everything is plain JVM: no hosted demo, no external services, ./gradlew build and you're done.

This is a portfolio project by Leon Lourenço, a senior backend engineer.

A few real numbers

Every claim below is copied verbatim from an actual local JMH/JaCoCo run — see each module's own README for the full table and how to reproduce it.

  • Bubble Sort, sorting the same 10,000-element array: random order is ~32,527x slower than already-sorted order, on the exact same code. That's the adaptive early-exit claim, made measurable.
  • Quick Sort with a randomized pivot, the same size: random order is only ~2.2x slower than already-sorted — not the 100x-plus a non-randomized quicksort would show on exactly that input. Proof the randomization actually neutralizes the classic worst-case risk.
  • Merge Sort and Heap Sort both stay within ~1.3–2x of each other across already-sorted, nearly-sorted, and random input at every size — the "guaranteed bound regardless of input order" claim, made measurable.
  • Binary Search against Linear Search on the same 1,000,000-element array: ~55,353x faster for the identical "is it there" question — the entire value of a sorted-data assumption, made measurable.
  • Fibonacci at n=35: naive recursion is ~6,057,544x slower than the tabulated version for the exact same answer — exponential vs. O(1) space, made measurable.
  • N-Queens at 8 queens: pruned backtracking is ~940x faster than brute force, and both agree on the same answer — the famous 92 solutions first published in 1850.

Why classic + applied + benchmark

A textbook implementation proves you understand an algorithm's mechanics — the loop invariant, the recursion, the partition step. It doesn't prove you know when to reach for it over the alternative, and it doesn't prove the textbook Big-O claim actually holds in a real JVM. So every module carries three things instead of one:

  • classic/ — the algorithm itself, hand-rolled (no relying on Arrays.sort/ Collections.sort as a shortcut), with tests that exercise its real edge cases (already sorted, reverse sorted, duplicates, the empty/single-element boundary).
  • applied/ — the same algorithm solving a real scenario, chosen by asking: what's the actual problem this algorithm solves, and where has that exact problem shown up? The mapping isn't fintech-only by default — it's deliberately pulled from wherever in the author's background (payments, insurance, telecom, mainframe modernization) the underlying problem is the most natural fit.
  • jmh/ — a JMH microbenchmark that measures the operation the module's complexity claim is about, usually as a direct A/B across input orderings: adaptive vs. not, guaranteed bound vs. average case. The numbers quoted in each README are copied from a real local run, not estimated.

Why Java?

Every module here is written in Java on purpose, not by default — it's the language this project's author ships in production daily, so implementing these algorithms without an Arrays.sort/Collections.sort shortcut is also a fluency demonstration, not just an algorithms one. That constraint is part of why Java specifically fits: the language ships a mature, highly-tuned sort as a one-line call, so deliberately writing around it is a real exercise. A language without that temptation built in — C, say — wouldn't pose quite the same choice.

The other reason is tooling maturity. Every benchmark number in this repo is measured, not estimated: JMH runs each benchmark through warmup iterations so the JIT has actually compiled the hot path before anything gets timed, forks a fresh JVM per benchmark to avoid cross-contamination, and uses blackholes to stop the JIT from optimizing away the very code being measured. JaCoCo brings the same rigor to coverage — 100% here means every instruction and branch genuinely ran under test. Building that level of methodological rigor from scratch in C is its own separate project; on the JVM it's ./gradlew jmh.

The honest tradeoff: JVM numbers include the JVM. JIT warm-up, garbage collection, and object header overhead are folded into every microsecond quoted in this repo. This repo doesn't pretend that layer is invisible; it leans on JMH's methodology specifically to see the algorithmic shape (adaptive vs. not, O(n log n) vs. O(n²)) through the JVM rather than around it.

The algorithms

Every module below carries the same classic/applied/benchmark implementation, its own README, and genuine 100% JaCoCo instruction + branch coverage.

Algorithm Category Applied scenario
Bubble Sort Sorting Legacy mainframe daily ledger correction (legacy bank)
Insertion Sort Sorting Call-detail-record batch sort (telecom)
Merge Sort Sorting Fraud compliance report ordering (fraud platform)
Quick Sort Sorting Claim reserve percentile sort (insurer)
Heap Sort Sorting Edge-equipment alarm sort (telecom)
Linear Search Searching Call-overage alert finder (telecom)
Binary Search Searching PIX-key snapshot lookup (PIX/BACEN)
Fibonacci Dynamic Programming Correspondent-bank payment route counting (telecom)
0/1 Knapsack Dynamic Programming Capex project selection (telecom)
Longest Common Subsequence Dynamic Programming Bank ledger reconciliation diff (legacy bank)
Coin Change Greedy ATM cash-out note dispensing (legacy bank)
Huffman Coding Greedy CDR batch compression (telecom)
Knuth-Morris-Pratt String Matching Watchlist narration scanning (fraud platform)
Euclidean GCD Math Split-payment ratio reduction (PIX/BACEN)
Sieve of Eratosthenes Math Dedup cache bucket sizing (fraud platform)
Fast Exponentiation Math Actuarial reserve growth projection (insurer)
N-Queens Backtracking Settlement lane assignment (PIX/BACEN)

Structure

Every algorithm module follows the same skeleton:

<category>/<algorithm>/
├── build.gradle.kts          # only present when the module needs extra dependencies
├── README.md                 # problem, solution, complexity, both examples, benchmark, coverage
└── src/
    ├── main/java/com/algorithms/<category>/<algorithm>/
    │   ├── classic/           # the from-scratch implementation
    │   └── applied/           # the real-scenario usage
    ├── test/java/...          # mirrors the classic/applied split
    └── jmh/java/com/algorithms/<category>/<algorithm>/benchmark/
        └── ...                # JMH microbenchmark(s) proving the complexity claim empirically

Tech stack

Java 26, Gradle 9.7 (Kotlin DSL, wrapper committed — ./gradlew works without installing Gradle), JUnit 5, AssertJ, JaCoCo 0.8.15, JMH 1.37. No Spring, no framework — every module is plain Java, since the point is the algorithm, not a container.

JMH wiring note: the community me.champeau.jmh Gradle plugin's last release (0.7.3, January 2025) is only tested up to Gradle 8.10/Java 21. Rather than fight a stale plugin against Gradle 9.7/Java 26, each module's src/jmh/java is wired directly as a plain Gradle source set (see the root build.gradle.kts) with JMH's own annotation processor generating the benchmark runner classes — no third-party plugin in the loop.

Running it

./gradlew build                                          # compiles every module
./gradlew test                                            # runs every module's tests
./gradlew :sorting:merge-sort:jacocoTestReport             # per-module coverage report (HTML)
./gradlew :sorting:merge-sort:jmh                          # per-module JMH benchmark run

No Docker, no database, no network calls — every test and benchmark runs against in-process code. Coverage and benchmark numbers quoted in each module's README are copied from a real local run (JDK 26.0.2 on this machine), not estimated.

Further reading

Books cited throughout this repo's individual module READMEs, gathered here for reference:

  • Cormen, Leiserson, Rivest & Stein — Introduction to Algorithms (CLRS), 3rd/4th ed. — the canonical academic reference; nearly every university algorithms course uses this book.
  • Sedgewick & Wayne — Algorithms, 4th ed. — Java-oriented and practical, from the Princeton course of the same name; the closest fit to this repo's own language and style.
  • Skiena — The Algorithm Design Manual — strong on "when to use what" and real case studies, the same spirit as this repo's own "When not to use it" sections.
  • Knuth — The Art of Computer Programming, Vol. 3 (Sorting and Searching) — the historical, canonical source for this repo's sorting and searching modules.
  • Kleinberg & Tardos — Algorithm Design — a strong reference specifically for the greedy and dynamic-programming design paradigms this repo's later modules cover.

License

MIT — see LICENSE.

About

The Grand Algorithms Project — classic algorithms (sorting, searching, DP, greedy, and more), each with a from-scratch Java implementation, a real-world applied example, and a JMH benchmark proving the complexity claim.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages