Rust高效前缀树实现库patricia_tree的使用,提供快速查找和插入的基数树数据结构
Rust高效前缀树实现库patricia_tree的使用,提供快速查找和插入的基数树数据结构
patricia_tree是一个基于基数树(也称为前缀树)的内存高效数据结构库。当键集合的前缀高度冗余时,基数树通过共享公共前缀路径可以显著减少内存使用量。
示例代码
以下是内容中提供的示例代码:
use patricia_tree::PatriciaMap;
let mut map = PatriciaMap::new();
map.insert("foo", 1);
map.insert("bar", 2);
map.insert("baz", 3);
assert_eq!(map.len(), 3);
assert_eq!(map.get("foo"), Some(&1));
assert_eq!(map.get("bar"), Some(&2));
assert_eq!(map.get("baz"), Some(&3));
完整示例
以下是一个更完整的示例,展示了patricia_tree库的基本用法:
use patricia_tree::PatriciaMap;
fn main() {
// 创建一个新的PatriciaMap
let mut map = PatriciaMap::new();
// 插入键值对
map.insert("apple", 10);
map.insert("app", 5);
map.insert("banana", 20);
map.insert("band", 15);
map.insert("orange", 30);
// 检查长度
println!("Map size: {}", map.len()); // 输出: Map size: 5
// 查找值
println!("Value for 'app': {:?}", map.get("app")); // 输出: Some(5)
println!("Value for 'apple': {:?}", map.get("apple")); // 输出: Some(10)
println!("Value for 'pear': {:?}", map.get("pear")); // 输出: None
// 检查键是否存在
println!("Contains 'banana': {}", map.contains_key("banana")); // 输出: true
println!("Contains 'grape': {}", map.contains_key("grape")); // 输出: false
// 删除键
map.remove("band");
println!("After removal, contains 'band': {}", map.contains_key("band")); // 输出: false
println!("Map size after removal: {}", map.len()); // 输出: Map size after removal: 4
// 遍历所有键值对
println!("All entries:");
for (key, value) in &map {
println!(" {:?}: {}", String::from_utf8_lossy(key), value);
}
}
性能基准
根据提供的基准测试数据,patricia_tree在内存使用方面表现优异:
-
对于Wikipedia标题数据集(1345万行):
- HashSet: 978MB
- BTreeSet: 1,086MB
- PatriciaSet: 424MB
-
对于Google 5-gram数据集(981万行):
- HashSet: 1,089MB
- BTreeSet: 920MB
- PatriciaSet: 218MB
安装
在项目中添加以下依赖到Cargo.toml:
patricia_tree = "0.9.0"
或者运行命令:
cargo add patricia_tree
许可证
该项目使用MIT许可证。
1 回复
Rust高效前缀树实现库patricia_tree使用指南
简介
patricia_tree
是Rust中一个高效的前缀树(基数树/Patricia trie)实现库。它提供了快速查找和插入操作,特别适合需要前缀匹配的场景,如IP路由表、自动补全、字典实现等。
主要特性
- 基于基数树(radix tree)实现,空间效率高
- 支持快速的键值插入和查找
- 提供前缀搜索功能
- 线程安全(支持多线程环境)
- 低内存开销
安装
在Cargo.toml中添加依赖:
[dependencies]
patricia_tree = "0.3"
基本使用方法
创建和插入元素
use patricia_tree::PatriciaMap;
fn main() {
// 创建一个新的前缀树映射
let mut tree = PatriciaMap::new();
// 插入键值对
tree.insert("apple", 1);
tree.insert("app", 2);
tree.insert("banana", 3);
tree.insert("band", 4);
println!("Tree size: {}", tree.len()); // 输出: Tree size: 4
}
查找元素
use patricia_tree::PatriciaMap;
fn main() {
let mut tree = PatriciaMap::new();
tree.insert("apple", 1);
tree.insert("app", 2);
// 精确查找
if let Some(value) = tree.get("apple") {
println!("Found apple: {}", value); // 输出: Found apple: 1
}
// 检查键是否存在
println!("Contains 'app': {}", tree.contains_key("app")); // 输出: Contains 'app': true
}
前缀搜索
use patricia_tree::PatriciaMap;
fn main() {
let mut tree = PatriciaMap::new();
tree.insert("apple", 1);
tree.insert("app", 2);
tree.insert("application", 3);
tree.insert("banana", 4);
// 查找所有以"app"为前缀的键值对
let prefix_matches: Vec<_> = tree.iter_prefix("app").collect();
println!("Prefix 'app' matches: {:?}", prefix_matches);
// 输出: Prefix 'app' matches: [("app", 2), ("apple", 1), ("application", 3)]
}
删除元素
use patricia_tree::PatriciaMap;
fn main() {
let mut tree = PatriciaMap::new();
tree.insert("apple", 1);
tree.insert("app", 2);
// 删除键
let removed = tree.remove("app");
println!("Removed value: {:?}", removed); // 输出: Removed value: Some(2)
println!("Contains 'app': {}", tree.contains_key("app")); // 输出: Contains 'app': false
}
高级用法
最长前缀匹配
use patricia_tree::PatriciaMap;
fn main() {
let mut tree = PatriciaMap::new();
tree.insert("192.168.1.0/24", "Network 1");
tree.insert("192.168.0.0/16", "Network 2");
// 查找最长匹配前缀
if let Some((prefix, value)) = tree.get_longest_common_prefix("192.168.1.100") {
println!("Longest prefix match: {} => {}", prefix, value);
// 输出: Longest prefix match: 192.168.1.0/24 => Network 1
}
}
遍历所有元素
use patricia_tree::PatriciaMap;
fn main() {
let mut tree = PatriciaMap::new();
tree.insert("apple", 1);
tree.insert("banana", 2);
tree.insert("cherry", 3);
// 遍历所有键值对
for (key, value) in &tree {
println!("{}: {}", key, value);
}
// 输出:
// apple: 1
// banana: 2
// cherry: 3
}
性能提示
- 对于大量数据,考虑使用
PatriciaMap
而不是标准库的HashMap
,特别是当键有共同前缀时 - 前缀搜索操作非常高效,适合实现自动补全功能
- 对于IP路由表等场景,最长前缀匹配功能特别有用
总结
patricia_tree
库提供了Rust中高效的前缀树实现,特别适合需要前缀匹配和搜索的场景。它的API设计简洁,性能优越,是处理字符串或字节序列键值对的理想选择。
完整示例
下面是一个完整的示例,展示了patricia_tree
库的主要功能:
use patricia_tree::PatriciaMap;
fn main() {
// 1. 创建和插入元素
let mut tree = PatriciaMap::new();
tree.insert("apple", 1);
tree.insert("app", 2);
tree.insert("application", 3);
tree.insert("banana", 4);
tree.insert("band", 5);
// 2. 查找元素
println!("=== 查找元素 ===");
if let Some(value) = tree.get("apple") {
println!("找到apple: {}", value);
}
println!("包含'app': {}", tree.contains_key("app"));
// 3. 前缀搜索
println!("\n=== 前缀搜索 ===");
let prefix_matches: Vec<_> = tree.iter_prefix("app").collect();
println!("'app'前缀匹配: {:?}", prefix_matches);
// 4. 删除元素
println!("\n=== 删除元素 ===");
let removed = tree.remove("app");
println!("删除'app': {:?}", removed);
println!("删除后包含'app': {}", tree.contains_key("app"));
// 5. 最长前缀匹配
println!("\n=== 最长前缀匹配 ===");
let mut ip_tree = PatriciaMap::new();
ip_tree.insert("192.168.1.0/24", "局域网1");
ip_tree.insert("192.168.0.0/16", "局域网2");
if let Some((prefix, value)) = ip_tree.get_longest_common_prefix("192.168.1.100") {
println!("最长前缀匹配: {} => {}", prefix, value);
}
// 6. 遍历所有元素
println!("\n=== 遍历所有元素 ===");
for (key, value) in &tree {
println!("{}: {}", key, value);
}
// 7. 树的基本信息
println!("\n=== 树信息 ===");
println!("树大小: {}", tree.len());
println!("是否为空: {}", tree.is_empty());
}
这个完整示例展示了:
- 创建前缀树和插入元素
- 精确查找和存在性检查
- 前缀搜索功能
- 删除元素操作
- 最长前缀匹配(模拟IP路由表场景)
- 遍历所有元素
- 获取树的基本信息
输出结果类似于:
=== 查找元素 ===
找到apple: 1
包含'app': true
=== 前缀搜索 ===
'app'前缀匹配: [("app", 2), ("apple", 1), ("application", 3)]
=== 删除元素 ===
删除'app': Some(2)
删除后包含'app': false
=== 最长前缀匹配 ===
最长前缀匹配: 192.168.1.0/24 => 局域网1
=== 遍历所有元素 ===
apple: 1
application: 3
banana: 4
band: 5
=== 树信息 ===
树大小: 4
是否为空: false