Skip to content

Commit cf020bf

Browse files
committed
docs: add trie examples and benchmarks
1 parent 76aa23b commit cf020bf

10 files changed

Lines changed: 231 additions & 0 deletions

File tree

Cargo.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,18 @@ path = "examples/soluciones/heap_top_k.rs"
8585
name = "solution_heap_dijkstra_frontier"
8686
path = "examples/soluciones/heap_dijkstra_frontier.rs"
8787

88+
[[example]]
89+
name = "solution_trie_trace_prefixes"
90+
path = "examples/soluciones/trie_trace_prefixes.rs"
91+
92+
[[example]]
93+
name = "solution_trie_autocomplete"
94+
path = "examples/soluciones/trie_autocomplete.rs"
95+
96+
[[example]]
97+
name = "solution_trie_unicode_policy"
98+
path = "examples/soluciones/trie_unicode_policy.rs"
99+
88100
[[bench]]
89101
name = "vector_bench"
90102
path = "benches/vector_bench.rs"
@@ -114,3 +126,8 @@ harness = false
114126
name = "heap_bench"
115127
path = "benches/heap_bench.rs"
116128
harness = false
129+
130+
[[bench]]
131+
name = "trie_bench"
132+
path = "benches/trie_bench.rs"
133+
harness = false

benches/trie_bench.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use rust_data_structures::trie::Trie;
2+
use std::collections::HashSet;
3+
use std::hint::black_box;
4+
use std::time::{Duration, Instant};
5+
6+
const SIZE: usize = 10_000;
7+
8+
fn main() {
9+
let words = generate_words();
10+
11+
println!("trie benchmark (manual, std::time::Instant)");
12+
println!("size: {SIZE}");
13+
println!("trie lookup: {:?}", bench_trie_lookup(&words));
14+
println!("hashset lookup: {:?}", bench_hashset_lookup(&words));
15+
println!("trie prefix search: {:?}", bench_trie_prefix_search(&words));
16+
println!(
17+
"sorted vector prefix search: {:?}",
18+
bench_sorted_vector_prefix_search(&words)
19+
);
20+
}
21+
22+
fn bench_trie_lookup(words: &[String]) -> Duration {
23+
let mut trie = Trie::new();
24+
for word in words {
25+
trie.insert(word);
26+
}
27+
28+
let start = Instant::now();
29+
for word in words {
30+
black_box(trie.contains(word));
31+
}
32+
start.elapsed()
33+
}
34+
35+
fn bench_hashset_lookup(words: &[String]) -> Duration {
36+
let set = words.iter().collect::<HashSet<_>>();
37+
38+
let start = Instant::now();
39+
for word in words {
40+
black_box(set.contains(word));
41+
}
42+
start.elapsed()
43+
}
44+
45+
fn bench_trie_prefix_search(words: &[String]) -> Duration {
46+
let mut trie = Trie::new();
47+
for word in words {
48+
trie.insert(word);
49+
}
50+
51+
let start = Instant::now();
52+
for prefix in ["course-0", "course-1", "course-9"] {
53+
black_box(trie.words_with_prefix(prefix));
54+
}
55+
start.elapsed()
56+
}
57+
58+
fn bench_sorted_vector_prefix_search(words: &[String]) -> Duration {
59+
let mut sorted = words.to_vec();
60+
sorted.sort();
61+
62+
let start = Instant::now();
63+
for prefix in ["course-0", "course-1", "course-9"] {
64+
let matches = sorted
65+
.iter()
66+
.filter(|word| word.starts_with(prefix))
67+
.collect::<Vec<_>>();
68+
black_box(matches);
69+
}
70+
start.elapsed()
71+
}
72+
73+
fn generate_words() -> Vec<String> {
74+
(0..SIZE).map(|index| format!("course-{index:05}")).collect()
75+
}

diagrams/07-trie.mmd

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
flowchart TB
2+
title["Trie: prefijos compartidos y terminales"]
3+
4+
root["root"]
5+
c["c"]
6+
a["a"]
7+
r["r terminal: car"]
8+
t1["t terminal: cart"]
9+
t2["t terminal: cat"]
10+
d["d"]
11+
o["o"]
12+
g["g terminal: dog"]
13+
14+
root --> c
15+
c --> a
16+
a --> r
17+
r --> t1
18+
a --> t2
19+
20+
root --> d
21+
d --> o
22+
o --> g
23+
24+
insert["insert(car)<br/>marca terminal al final"]
25+
lookup["contains(ca)<br/>existe prefijo, no terminal"]
26+
prefix["words_with_prefix(ca)<br/>recorre subarbol"]
27+
remove["remove(car)<br/>desmarca terminal y poda si queda sin hijos"]
28+
29+
insert --> r
30+
lookup --> a
31+
prefix --> a
32+
remove --> r
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use rust_data_structures::trie::Trie;
2+
3+
fn main() {
4+
let mut trie = Trie::new();
5+
for word in ["app", "apple", "apply", "apt", "backend"] {
6+
trie.insert(word);
7+
}
8+
9+
let suggestions = autocomplete(&trie, "ap", 3);
10+
11+
assert_eq!(suggestions, vec!["app", "apple", "apply"]);
12+
println!("{suggestions:?}");
13+
}
14+
15+
fn autocomplete(trie: &Trie, prefix: &str, limit: usize) -> Vec<String> {
16+
trie.words_with_prefix(prefix)
17+
.into_iter()
18+
.take(limit)
19+
.collect()
20+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use rust_data_structures::trie::Trie;
2+
3+
fn main() {
4+
let mut trie = Trie::new();
5+
trie.insert("car");
6+
trie.insert("cart");
7+
trie.insert("cat");
8+
9+
assert!(trie.contains("car"));
10+
assert!(!trie.contains("ca"));
11+
assert!(trie.starts_with("ca"));
12+
assert_eq!(trie.words_with_prefix("car"), vec!["car", "cart"]);
13+
14+
println!("{:?}", trie.words_with_prefix("ca"));
15+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use rust_data_structures::trie::Trie;
2+
3+
fn main() {
4+
let mut trie = Trie::new();
5+
trie.insert("é");
6+
trie.insert("e\u{301}");
7+
trie.insert("🚀rust");
8+
9+
assert!(trie.contains("é"));
10+
assert!(trie.contains("e\u{301}"));
11+
assert!(trie.starts_with("🚀"));
12+
assert_eq!(trie.words_with_prefix("🚀"), vec!["🚀rust"]);
13+
14+
println!("{:?}", trie.words_with_prefix(""));
15+
}

examples/trie_advanced.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
use rust_data_structures::trie::Trie;
2+
3+
fn main() {
4+
let mut trie = Trie::new();
5+
6+
trie.insert("tea");
7+
trie.insert("team");
8+
trie.insert("tear");
9+
trie.remove("tea");
10+
11+
println!("tea: {}", trie.contains("tea"));
12+
println!("team: {}", trie.contains("team"));
13+
println!("nodos internos: {}", trie.node_count());
14+
}

examples/trie_basic.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use rust_data_structures::trie::Trie;
2+
3+
fn main() {
4+
let mut dictionary = Trie::new();
5+
6+
dictionary.insert("rust");
7+
dictionary.insert("runner");
8+
dictionary.insert("route");
9+
10+
println!("contiene rust: {}", dictionary.contains("rust"));
11+
println!("prefijo ru: {}", dictionary.starts_with("ru"));
12+
}

examples/trie_intermediate.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use rust_data_structures::trie::Trie;
2+
3+
fn main() {
4+
let mut autocomplete = Trie::new();
5+
6+
autocomplete.insert("app");
7+
autocomplete.insert("apple");
8+
autocomplete.insert("apply");
9+
autocomplete.insert("backend");
10+
11+
println!("{:?}", autocomplete.words_with_prefix("app"));
12+
}

examples/trie_real_case.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
use rust_data_structures::trie::Trie;
2+
3+
fn main() {
4+
let mut routes = Trie::new();
5+
6+
routes.insert("/courses");
7+
routes.insert("/courses/rust-data-structures");
8+
routes.insert("/docs");
9+
10+
let request_path = "/courses/rust";
11+
println!(
12+
"rutas que empiezan con /courses: {:?}",
13+
routes.words_with_prefix("/courses")
14+
);
15+
println!(
16+
"request {request_path} comparte prefijo: {}",
17+
routes.starts_with("/courses")
18+
);
19+
}

0 commit comments

Comments
 (0)