从向量到哈希: Rust 的数据结构

Rust 标准库提供了Vec<T>HashMap<K, V>HashSet<T>等基本数据结构。这三种数据结构在大多数编程场景中最为常用,其设计符合 Rust 安全、并发的目标。

Vec<T>

Vec是 Rust 中最常用动态数组实现。

rust 复制代码
fn main() {
    // 创建空向量
    let mut numbers: Vec<i32> = Vec::new();

    // 使用宏创建并初始化向量
    let mut names = vec!["Alice", "Bob", "Carol"];

    // 向量添加元素
    numbers.push(1);
    numbers.push(2);
    numbers.push(3);

    numbers.pop(); // 移除并返回最后一个元素

    // 访问向量中的元素
    if let Some(first_name) = names.get(0) {
        println!("第一个名字是:{}", first_name);
    }

    // 遍历向量元素
    for name in &names {
        println!("{}", name);
    }

    // 修改向量中的元素
    if let Some(first_name) = names.get_mut(0) {
        *first_name = "Dave";
    }

    // 使用迭代器处理向量元素
    let numbers_squared: Vec<i32> = numbers.iter().map(|&x| x * x).collect();
    println!("平方数:{:?}", numbers_squared);

    // 用额外元素扩展向量
    numbers.extend([4, 5, 6].iter().copied());

    // 直接使用索引访问元素
    println!("第二个名字:{}", names[1]); // 注意:直接索引可能引发恐慌
}

向量适用于处理相同类型的元素序列,无论是字符串、整数还是自定义类型。

HashMap<K, V>

HashMap<K, V>使用哈希实现键值存储。

rust 复制代码
use std::collections::HashMap;

fn main() {
    // 创建空哈希表
    let mut book_reviews: HashMap<String, String> = HashMap::new();

    // 向哈希表中添加元素
    book_reviews.insert("The Hobbit".to_string(), "优秀的奇幻书籍".to_string());
    book_reviews.insert("The Catcher in the Rye".to_string(), "经典小说".to_string());

    // 访问哈希表中的元素
    if let Some(review) = book_reviews.get("The Hobbit") {
        println!("《霍比特人》的评论:{}", review);
    }

    // 从哈希表中移除元素
    book_reviews.remove("The Catcher in the Rye");

    // 遍历哈希表
    for (book, review) in &book_reviews {
        println!("{}: {}", book, review);
    }

    // 更新哈希表中的元素
    book_reviews.entry("The Hobbit".to_string()).or_insert("未找到评论".to_string());
    book_reviews.entry("1984".to_string()).or_insert("反乌托邦科幻小说".to_string());

    let mut scores = HashMap::new();

    // 使用 `insert` 直接插入
    scores.insert("Blue", 10);
    scores.insert("Blue", 25); // 覆盖之前的值

    // 使用 `entry` 更新或插入
    scores.entry("Yellow").or_insert(50); // 插入,因为 "Yellow" 不存在
    scores.entry("Blue").or_insert(50);   // 无操作,因为 "Blue" 已存在

    // 结果:{"Blue": 25, "Yellow": 50}

    // 检查键是否存在
    if book_reviews.contains_key("1984") {
        println!("1984 的评论可用。");
    }
}

HashSet<T>

HashSet是存储不重复元素的无序集合。它使用哈希表实现,提供查找、插入和删除操作。

rust 复制代码
use std::collections::HashSet;

fn main() {
    // 创建空集合
    let mut numbers = HashSet::new();

    // 向集合中添加元素
    numbers.insert(1);
    numbers.insert(2);
    numbers.insert(3);

    // 从集合中移除元素
    numbers.remove(&3);

    // 检查元素是否存在于集合中
    if numbers.contains(&1) {
        println!("1 在集合中");
    }

    // 遍历集合
    for number in &numbers {
        println!("{}", number);
    }

    // 集合操作:并集、交集、差集、对称差集

    // 此时,numbers 包含 {1, 2}

    let other_numbers = [2, 3, 4].iter().cloned().collect::<HashSet<_>>();
    // other_numbers 包含 {2, 3, 4}

    let union = numbers.union(&other_numbers).cloned().collect::<HashSet<_>>();
    println!("并集:{:?}", union);
    // 并集:`{1, 2, 3, 4}`(两个集合中的所有唯一元素)

    let intersection = numbers.intersection(&other_numbers).cloned().collect::<HashSet<_>>();
    println!("交集:{:?}", intersection);
    // 交集:`{2}`(共同元素)

    let difference = numbers.difference(&other_numbers).cloned().collect::<HashSet<_>>();
    println!("差集:{:?}", difference);
    // 差集:`{1}`(在 `numbers` 中但不在 `other_numbers` 中的元素)

    let symmetric_difference = numbers.symmetric_difference(&other_numbers).cloned().collect::<HashSet<_>>();
    println!("对称差集:{:?}", symmetric_difference);
    // 对称差集:`{1, 3, 4}`(每个集合中唯一的元素)
}

双向链表(LinkedList<T>

LinkedList<T> 是 Rust 标准库提供的双向链表。与向量(Vec<T>)相比,链表允许插入和删除元素,尤其是在列表开头或结尾处。然而,它们在随机访问方面表现不佳。

rust 复制代码
use std::collections::LinkedList;

fn main() {
    // 创建新的空链表
    let mut list: LinkedList<i32> = LinkedList::new();

    // 向列表尾部添加元素
    list.push_back(1);
    list.push_back(2);

    // 向列表头部添加元素
    list.push_front(0);

    // 从列表头部和尾部弹出元素
    assert_eq!(list.pop_front(), Some(0));
    assert_eq!(list.pop_back(), Some(2));

    // 遍历列表
    for elem in list.iter() {
        println!("{}", elem);
    }

    // 修改列表中的元素(需要使用迭代器)
    let mut iter_mut = list.iter_mut();
    if let Some(first_elem) = iter_mut.next() {
        *first_elem = 3;
    }

    // 打印修改后的列表
    println!("修改后的列表:{:?}", list);
}

当需要频繁在列表开头或结尾处添加或删除元素时,LinkedList 是不错的选择,因为这些操作的时间复杂度为 O(1)。

如果应用程序很少需要随机访问,那么链表比向量更合适。

BTreeMap<K, V>

BTreeMap<K, V> 使用 B 树实现键值集合。它保持键的排序顺序。与哈希表(HashMap<K, V>)相比,BTreeMap 在有序遍历时表现出色。

rust 复制代码
use std::collections::BTreeMap;

fn main() {
    // 创建新的空 BTreeMap
    let mut map: BTreeMap<String, i32> = BTreeMap::new();

    // 向 BTreeMap 中插入键值对
    map.insert("apple".to_string(), 3);
    map.insert("banana".to_string(), 2);
    map.insert("pear".to_string(), 4);

    // 获取对应键的值
    if let Some(v) = map.get("apple") {
        println!("apple: {}", v);
    }

    // 移除键值对
    map.remove("banana");

    // 遍历 BTreeMap
    for (key, value) in &map {
        println!("{}: {}", key, value);
    }

    // 范围查询:获取 "apple" 和 "pear"(含)之间所有键值对
    let range = map.range("apple".to_string()..="pear".to_string());
    for (key, value) in range {
        println!("范围查询:{}: {}", key, value);
    }
}

当需要自动排序时,BTreeMap 是不错的选择。

如果程序频繁进行有序的查找、插入和删除操作,BTreeMap 可能比 HashMap 更合适,因为它保持键的顺序,便于有序遍历。

B 树集(BTreeSet<T>

BTreeSet<T> 基于 B 树实现的集合。它存储唯一元素并保持其排序顺序。与 HashSet<T> 相比,BTreeSet 支持有序操作和范围查询,但某些操作可能较慢。

rust 复制代码
use std::collections::BTreeSet;

fn main() {
    // 创建新的空 BTreeSet
    let mut set: BTreeSet<i32> = BTreeSet::new();

    // 向集合中添加元素
    set.insert(12);
    set.insert(5);
    set.insert(18);

    // 检查元素是否存在
    if set.contains(&12) {
        println!("集合包含 12");
    }

    // 移除元素
    set.remove(&5);

    // 遍历集合(元素将按升序排列)
    for num in &set {
        println!("{}", num);
    }

    // 范围查询:获取大于等于 10 且小于 20 的所有元素
    for num in set.range(10..20) {
        println!("范围查询:{}", num);
    }
}

当需要有序集合进行快速查找、范围查询或有序遍历时,BTreeSet 是不错的选择。

BinaryHeap<T>

BinaryHeap<T> 是基于二叉堆实现的优先队列。它允许快速插入元素和移除最大(或最小)元素,具体取决于它是最大堆还是最小堆。默认情况下,Rust 的 BinaryHeap 是最大堆。

rust 复制代码
use std::collections::BinaryHeap;

fn main() {
    // 创建新的空 BinaryHeap
    let mut heap = BinaryHeap::new();

    // 向堆中添加元素
    heap.push(1);
    heap.push(5);
    heap.push(2);

    // 查看堆中的最大元素而不移除它
    if let Some(max) = heap.peek() {
        println!("最大元素:{}", max);
    }

    // 移除并返回最大元素
    println!("移除的最大元素:{}", heap.pop().unwrap());

    // 遍历堆(迭代顺序未排序)
    for num in &heap {
        println!("{}", num);
    }
}

当需要快速访问和移除最大(或最小)元素时,BinaryHeap 理想选择。这在 Dijkstra 最短路径等算法中尤为有用。

BinaryHeap 适用于任务调度、贪心算法或任何需要优先队列的场景。

原文:dev.to/leapcell/fr...

相关推荐
红尘散仙4 小时前
二、WebGPU 基础入门——基础知识
rust·typescript·gpu
Source.Liu5 小时前
【CXX】6.3 &[T], &mut [T] — rust::Slice<T>
rust·cxx
红尘散仙5 小时前
一、WebGPU 基础入门——环境搭建
rust·typescript·gpu
机构师9 小时前
<rust><tauri><GUI>基于tauri和rust,编写一个二维码生成器
javascript·rust
HelloReader9 小时前
使用Cargo打开Rust世界大门(三)
rust
Source.Liu1 天前
【CXX】6 内置绑定
qt·rust·cxx
Source.Liu1 天前
【CXX】6.2 &str — rust::Str
c++·rust·cxx
冬冬小圆帽2 天前
从零到一:如何系统化封装并发布 React 组件库到 npm
react.js·rust·npm
Source.Liu2 天前
【学写LibreCAD】 2.1 pdf_print_loop文件
qt·rust·pdf·cad·dxf