Skip to content

Commit 2215e4b

Browse files
committed
docs: add graph examples and benchmarks
1 parent 9c60800 commit 2215e4b

10 files changed

Lines changed: 319 additions & 0 deletions

Cargo.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,18 @@ path = "examples/soluciones/trie_autocomplete.rs"
9797
name = "solution_trie_unicode_policy"
9898
path = "examples/soluciones/trie_unicode_policy.rs"
9999

100+
[[example]]
101+
name = "solution_graph_dependency_edges"
102+
path = "examples/soluciones/graph_dependency_edges.rs"
103+
104+
[[example]]
105+
name = "solution_graph_social_neighbors"
106+
path = "examples/soluciones/graph_social_neighbors.rs"
107+
108+
[[example]]
109+
name = "solution_graph_route_matrix"
110+
path = "examples/soluciones/graph_route_matrix.rs"
111+
100112
[[bench]]
101113
name = "vector_bench"
102114
path = "benches/vector_bench.rs"
@@ -131,3 +143,8 @@ harness = false
131143
name = "trie_bench"
132144
path = "benches/trie_bench.rs"
133145
harness = false
146+
147+
[[bench]]
148+
name = "graph_bench"
149+
path = "benches/graph_bench.rs"
150+
harness = false

benches/graph_bench.rs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
use rust_data_structures::graph::{AdjacencyMatrix, Graph};
2+
use std::hint::black_box;
3+
use std::time::{Duration, Instant};
4+
5+
const SIZE: i32 = 700;
6+
7+
fn main() {
8+
println!("graph benchmark (manual, std::time::Instant)");
9+
println!("size: {SIZE}");
10+
println!(
11+
"adjacency list sparse build: {:?}",
12+
bench_list_sparse_build()
13+
);
14+
println!(
15+
"adjacency matrix sparse build: {:?}",
16+
bench_matrix_sparse_build()
17+
);
18+
println!("adjacency list edge query: {:?}", bench_list_edge_query());
19+
println!(
20+
"adjacency matrix edge query: {:?}",
21+
bench_matrix_edge_query()
22+
);
23+
println!(
24+
"adjacency list neighbor scan: {:?}",
25+
bench_list_neighbor_scan()
26+
);
27+
}
28+
29+
fn bench_list_sparse_build() -> Duration {
30+
let start = Instant::now();
31+
black_box(build_list());
32+
start.elapsed()
33+
}
34+
35+
fn bench_matrix_sparse_build() -> Duration {
36+
let start = Instant::now();
37+
black_box(build_matrix());
38+
start.elapsed()
39+
}
40+
41+
fn bench_list_edge_query() -> Duration {
42+
let graph = build_list();
43+
44+
let start = Instant::now();
45+
for node in 0..SIZE {
46+
black_box(graph.has_edge(node, (node + 1) % SIZE));
47+
}
48+
start.elapsed()
49+
}
50+
51+
fn bench_matrix_edge_query() -> Duration {
52+
let graph = build_matrix();
53+
54+
let start = Instant::now();
55+
for node in 0..SIZE {
56+
black_box(graph.has_edge(node, (node + 1) % SIZE));
57+
}
58+
start.elapsed()
59+
}
60+
61+
fn bench_list_neighbor_scan() -> Duration {
62+
let graph = build_list();
63+
64+
let start = Instant::now();
65+
for node in 0..SIZE {
66+
black_box(graph.neighbors(node));
67+
}
68+
start.elapsed()
69+
}
70+
71+
fn build_list() -> Graph<i32> {
72+
let mut graph = Graph::new_directed();
73+
74+
for node in 0..SIZE {
75+
graph.add_node(node);
76+
}
77+
78+
for node in 0..SIZE {
79+
graph.add_edge(node, (node + 1) % SIZE, 1).unwrap();
80+
graph.add_edge(node, (node + 7) % SIZE, 1).unwrap();
81+
}
82+
83+
graph
84+
}
85+
86+
fn build_matrix() -> AdjacencyMatrix<i32> {
87+
let mut graph = AdjacencyMatrix::new_directed();
88+
89+
for node in 0..SIZE {
90+
graph.add_node(node);
91+
}
92+
93+
for node in 0..SIZE {
94+
graph.add_edge(node, (node + 1) % SIZE, 1).unwrap();
95+
graph.add_edge(node, (node + 7) % SIZE, 1).unwrap();
96+
}
97+
98+
graph
99+
}

diagrams/08-graph.mmd

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
flowchart TB
2+
title["Graph: representaciones y operaciones"]
3+
4+
subgraph logical["Modelo logico"]
5+
a["Nodo A"]
6+
b["Nodo B"]
7+
c["Nodo C"]
8+
a -- "peso 7" --> b
9+
b -- "peso 2" --> c
10+
c -- "peso 4" --> a
11+
end
12+
13+
subgraph list["Lista de adyacencia"]
14+
la["A: [(B, 7)]"]
15+
lb["B: [(C, 2)]"]
16+
lc["C: [(A, 4)]"]
17+
end
18+
19+
subgraph matrix["Matriz de adyacencia"]
20+
m1["A,B = 7"]
21+
m2["B,C = 2"]
22+
m3["C,A = 4"]
23+
m4["celdas vacias = sin arista"]
24+
end
25+
26+
subgraph edge_list["Lista de aristas"]
27+
e1["(A, B, 7)"]
28+
e2["(B, C, 2)"]
29+
e3["(C, A, 4)"]
30+
end
31+
32+
logical --> list
33+
logical --> matrix
34+
logical --> edge_list
35+
36+
choose_sparse["Grafo disperso<br/>pocas aristas por nodo"]
37+
choose_dense["Grafo denso<br/>muchas consultas de existencia"]
38+
choose_export["Serializacion o auditoria<br/>recorrer aristas"]
39+
40+
choose_sparse --> list
41+
choose_dense --> matrix
42+
choose_export --> edge_list

examples/graph_advanced.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use rust_data_structures::graph::{AdjacencyMatrix, Graph};
2+
3+
fn main() {
4+
let nodes = ["a", "b", "c", "d"];
5+
let routes = [
6+
("a", "b", 10),
7+
("a", "c", 15),
8+
("b", "c", 3),
9+
("c", "d", 7),
10+
("d", "a", 20),
11+
];
12+
13+
let mut list = Graph::new_directed();
14+
let mut matrix = AdjacencyMatrix::new_directed();
15+
16+
for node in nodes {
17+
list.add_node(node);
18+
matrix.add_node(node);
19+
}
20+
21+
for (from, to, weight) in routes {
22+
list.add_edge(from, to, weight).unwrap();
23+
matrix.add_edge(from, to, weight).unwrap();
24+
}
25+
26+
println!("lista: vecinos de a = {:?}", list.neighbors("a").unwrap());
27+
println!("matriz: peso a->c = {:?}", matrix.edge_weight("a", "c"));
28+
println!("matriz: existe b->d = {}", matrix.has_edge("b", "d"));
29+
}

examples/graph_basic.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
use rust_data_structures::graph::Graph;
2+
3+
fn main() {
4+
let mut dependencies = Graph::new_directed();
5+
6+
dependencies.add_node("lexer");
7+
dependencies.add_node("parser");
8+
dependencies.add_node("type-checker");
9+
10+
dependencies.add_edge("parser", "lexer", 1).unwrap();
11+
dependencies.add_edge("type-checker", "parser", 1).unwrap();
12+
13+
println!("nodos: {}", dependencies.node_count());
14+
println!("aristas: {}", dependencies.edge_count());
15+
println!(
16+
"parser depende de lexer: {}",
17+
dependencies.has_edge("parser", "lexer")
18+
);
19+
println!(
20+
"lexer depende de parser: {}",
21+
dependencies.has_edge("lexer", "parser")
22+
);
23+
}

examples/graph_intermediate.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use rust_data_structures::graph::Graph;
2+
3+
fn main() {
4+
let mut social = Graph::new_undirected();
5+
6+
for person in ["ana", "beatriz", "carlos", "diego"] {
7+
social.add_node(person);
8+
}
9+
10+
social.add_edge("ana", "beatriz", 5).unwrap();
11+
social.add_edge("ana", "carlos", 2).unwrap();
12+
social.add_edge("beatriz", "diego", 1).unwrap();
13+
14+
println!("amistades logicas: {}", social.edge_count());
15+
println!("vecinos de ana: {:?}", social.neighbors("ana").unwrap());
16+
println!("beatriz ve a ana: {}", social.has_edge("beatriz", "ana"));
17+
}

examples/graph_real_case.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use rust_data_structures::graph::Graph;
2+
3+
fn main() {
4+
let mut course_map = Graph::new_directed();
5+
6+
for course in [
7+
"rust-basics",
8+
"ownership",
9+
"data-structures",
10+
"algorithms",
11+
"distributed-systems",
12+
] {
13+
course_map.add_node(course);
14+
}
15+
16+
course_map.add_edge("ownership", "rust-basics", 1).unwrap();
17+
course_map
18+
.add_edge("data-structures", "ownership", 1)
19+
.unwrap();
20+
course_map
21+
.add_edge("algorithms", "data-structures", 1)
22+
.unwrap();
23+
course_map
24+
.add_edge("distributed-systems", "algorithms", 1)
25+
.unwrap();
26+
27+
for edge in course_map.edges() {
28+
println!("{} requiere {}", edge.from, edge.to);
29+
}
30+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
use rust_data_structures::graph::Graph;
2+
3+
fn main() {
4+
let mut graph = Graph::new_directed();
5+
6+
for crate_name in ["api", "domain", "database", "observability"] {
7+
graph.add_node(crate_name);
8+
}
9+
10+
graph.add_edge("api", "domain", 1).unwrap();
11+
graph.add_edge("api", "observability", 1).unwrap();
12+
graph.add_edge("database", "domain", 1).unwrap();
13+
14+
let edges = graph.edges();
15+
16+
assert_eq!(edges.len(), 3);
17+
assert!(graph.has_edge("api", "domain"));
18+
assert!(!graph.has_edge("domain", "api"));
19+
20+
for edge in edges {
21+
println!("{} -> {}", edge.from, edge.to);
22+
}
23+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use rust_data_structures::graph::AdjacencyMatrix;
2+
3+
fn main() {
4+
let mut routes = AdjacencyMatrix::new_directed();
5+
6+
for city in ["mxn", "gdl", "qro"] {
7+
routes.add_node(city);
8+
}
9+
10+
routes.add_edge("mxn", "gdl", 9).unwrap();
11+
routes.add_edge("gdl", "qro", 5).unwrap();
12+
13+
assert_eq!(routes.edge_weight("mxn", "gdl"), Some(9));
14+
assert!(!routes.has_edge("qro", "mxn"));
15+
assert_eq!(routes.node_count(), 3);
16+
17+
println!("mxn -> gdl: {:?}", routes.edge_weight("mxn", "gdl"));
18+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use rust_data_structures::graph::Graph;
2+
3+
fn main() {
4+
let mut graph = Graph::new_undirected();
5+
6+
for person in ["ana", "beatriz", "carlos", "diego"] {
7+
graph.add_node(person);
8+
}
9+
10+
graph.add_edge("ana", "beatriz", 10).unwrap();
11+
graph.add_edge("ana", "carlos", 4).unwrap();
12+
graph.add_edge("diego", "beatriz", 2).unwrap();
13+
14+
let ana_neighbors = graph.neighbors("ana").unwrap();
15+
16+
assert_eq!(ana_neighbors, vec![("beatriz", 10), ("carlos", 4)]);
17+
assert!(graph.has_edge("beatriz", "ana"));
18+
assert_eq!(graph.edge_count(), 3);
19+
20+
println!("vecinos de ana: {ana_neighbors:?}");
21+
}

0 commit comments

Comments
 (0)