Skip to content

Commit 155c767

Browse files
authored
Improve Trie (TheAlgorithms#803)
* ref: improve Trie * docs: do not specify the used language
1 parent aad5192 commit 155c767

File tree

1 file changed

+81
-23
lines changed

1 file changed

+81
-23
lines changed

src/data_structures/trie.rs

Lines changed: 81 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,29 @@
1+
//! This module provides a generic implementation of a Trie (prefix tree).
2+
//! A Trie is a tree-like data structure that is commonly used to store sequences of keys
3+
//! (such as strings, integers, or other iterable types) where each node represents one element
4+
//! of the key, and values can be associated with full sequences.
5+
16
use std::collections::HashMap;
27
use std::hash::Hash;
38

9+
/// A single node in the Trie structure, representing a key and an optional value.
410
#[derive(Debug, Default)]
511
struct Node<Key: Default, Type: Default> {
12+
/// A map of children nodes where each key maps to another `Node`.
613
children: HashMap<Key, Node<Key, Type>>,
14+
/// The value associated with this node, if any.
715
value: Option<Type>,
816
}
917

18+
/// A generic Trie (prefix tree) data structure that allows insertion and lookup
19+
/// based on a sequence of keys.
1020
#[derive(Debug, Default)]
1121
pub struct Trie<Key, Type>
1222
where
1323
Key: Default + Eq + Hash,
1424
Type: Default,
1525
{
26+
/// The root node of the Trie, which does not hold a value itself.
1627
root: Node<Key, Type>,
1728
}
1829

@@ -21,12 +32,21 @@ where
2132
Key: Default + Eq + Hash,
2233
Type: Default,
2334
{
35+
/// Creates a new, empty `Trie`.
36+
///
37+
/// # Returns
38+
/// A `Trie` instance with an empty root node.
2439
pub fn new() -> Self {
2540
Self {
2641
root: Node::default(),
2742
}
2843
}
2944

45+
/// Inserts a value into the Trie, associating it with a sequence of keys.
46+
///
47+
/// # Arguments
48+
/// - `key`: An iterable sequence of keys (e.g., characters in a string or integers in a vector).
49+
/// - `value`: The value to associate with the sequence of keys.
3050
pub fn insert(&mut self, key: impl IntoIterator<Item = Key>, value: Type)
3151
where
3252
Key: Eq + Hash,
@@ -38,60 +58,98 @@ where
3858
node.value = Some(value);
3959
}
4060

61+
/// Retrieves a reference to the value associated with a sequence of keys, if it exists.
62+
///
63+
/// # Arguments
64+
/// - `key`: An iterable sequence of keys (e.g., characters in a string or integers in a vector).
65+
///
66+
/// # Returns
67+
/// An `Option` containing a reference to the value if the sequence of keys exists in the Trie,
68+
/// or `None` if it does not.
4169
pub fn get(&self, key: impl IntoIterator<Item = Key>) -> Option<&Type>
4270
where
4371
Key: Eq + Hash,
4472
{
4573
let mut node = &self.root;
4674
for c in key {
47-
if node.children.contains_key(&c) {
48-
node = node.children.get(&c).unwrap()
49-
} else {
50-
return None;
51-
}
75+
node = node.children.get(&c)?;
5276
}
5377
node.value.as_ref()
5478
}
5579
}
5680

5781
#[cfg(test)]
5882
mod tests {
59-
6083
use super::*;
6184

6285
#[test]
63-
fn test_insertion() {
86+
fn test_insertion_and_retrieval_with_strings() {
6487
let mut trie = Trie::new();
65-
assert_eq!(trie.get("".chars()), None);
6688

6789
trie.insert("foo".chars(), 1);
90+
assert_eq!(trie.get("foo".chars()), Some(&1));
6891
trie.insert("foobar".chars(), 2);
92+
assert_eq!(trie.get("foobar".chars()), Some(&2));
93+
assert_eq!(trie.get("foo".chars()), Some(&1));
94+
trie.insert("bar".chars(), 3);
95+
assert_eq!(trie.get("bar".chars()), Some(&3));
96+
assert_eq!(trie.get("baz".chars()), None);
97+
assert_eq!(trie.get("foobarbaz".chars()), None);
98+
}
6999

100+
#[test]
101+
fn test_insertion_and_retrieval_with_integers() {
70102
let mut trie = Trie::new();
71-
assert_eq!(trie.get(vec![1, 2, 3]), None);
72103

73104
trie.insert(vec![1, 2, 3], 1);
74-
trie.insert(vec![3, 4, 5], 2);
105+
assert_eq!(trie.get(vec![1, 2, 3]), Some(&1));
106+
trie.insert(vec![1, 2, 3, 4, 5], 2);
107+
assert_eq!(trie.get(vec![1, 2, 3, 4, 5]), Some(&2));
108+
assert_eq!(trie.get(vec![1, 2, 3]), Some(&1));
109+
trie.insert(vec![10, 20, 30], 3);
110+
assert_eq!(trie.get(vec![10, 20, 30]), Some(&3));
111+
assert_eq!(trie.get(vec![4, 5, 6]), None);
112+
assert_eq!(trie.get(vec![1, 2, 3, 4, 5, 6]), None);
75113
}
76114

77115
#[test]
78-
fn test_get() {
116+
fn test_empty_trie() {
117+
let trie: Trie<char, i32> = Trie::new();
118+
119+
assert_eq!(trie.get("foo".chars()), None);
120+
assert_eq!(trie.get("".chars()), None);
121+
}
122+
123+
#[test]
124+
fn test_insert_empty_key() {
125+
let mut trie: Trie<char, i32> = Trie::new();
126+
127+
trie.insert("".chars(), 42);
128+
assert_eq!(trie.get("".chars()), Some(&42));
129+
assert_eq!(trie.get("foo".chars()), None);
130+
}
131+
132+
#[test]
133+
fn test_overlapping_keys() {
79134
let mut trie = Trie::new();
80-
trie.insert("foo".chars(), 1);
81-
trie.insert("foobar".chars(), 2);
82-
trie.insert("bar".chars(), 3);
83-
trie.insert("baz".chars(), 4);
84135

85-
assert_eq!(trie.get("foo".chars()), Some(&1));
86-
assert_eq!(trie.get("food".chars()), None);
136+
trie.insert("car".chars(), 1);
137+
trie.insert("cart".chars(), 2);
138+
trie.insert("carter".chars(), 3);
139+
assert_eq!(trie.get("car".chars()), Some(&1));
140+
assert_eq!(trie.get("cart".chars()), Some(&2));
141+
assert_eq!(trie.get("carter".chars()), Some(&3));
142+
assert_eq!(trie.get("care".chars()), None);
143+
}
87144

145+
#[test]
146+
fn test_partial_match() {
88147
let mut trie = Trie::new();
89-
trie.insert(vec![1, 2, 3, 4], 1);
90-
trie.insert(vec![42], 2);
91-
trie.insert(vec![42, 6, 1000], 3);
92-
trie.insert(vec![1, 2, 4, 16, 32], 4);
93148

94-
assert_eq!(trie.get(vec![42, 6, 1000]), Some(&3));
95-
assert_eq!(trie.get(vec![43, 44, 45]), None);
149+
trie.insert("apple".chars(), 10);
150+
assert_eq!(trie.get("app".chars()), None);
151+
assert_eq!(trie.get("appl".chars()), None);
152+
assert_eq!(trie.get("apple".chars()), Some(&10));
153+
assert_eq!(trie.get("applepie".chars()), None);
96154
}
97155
}

0 commit comments

Comments
 (0)