3.15.5 LinkedList(链表)

Rust 中的 LinkedList(链表)是一种线性数据结构,它由一系列相互连接的节点组成。每个节点都包含一个元素和指向前一个节点和后一个节点的指针。这是有关 Rust LinkedList 的一些详细信息:

1. 创建 LinkedList:

要创建一个新的空 LinkedList,可以使用 LinkedList::new() 方法。需要导入 std::collections::LinkedList 模块以使用 LinkedList。

#![allow(unused)]
fn main() {
use std::collections::LinkedList;

let mut list = LinkedList::new();
}

2. 添加元素:

可以使用 push_front()push_back() 方法将元素添加到链表的开头和结尾。

#![allow(unused)]
fn main() {
list.push_front(1);
list.push_back(2);
}

3. 访问元素:

可以使用 front()back() 方法分别访问链表的第一个和最后一个元素。这些方法返回一个 Option<&T> 类型,如果链表不为空,则返回 Some(&element),否则返回 None

#![allow(unused)]
fn main() {
let first_element = list.front(); // 返回 Option<&T>
let last_element = list.back(); // 返回 Option<&T>
}

还可以使用 front_mut() 和 back_mut() 方法获取可变引用。

4. 删除元素:

可以使用 pop_front()pop_back() 方法分别删除并返回链表的第一个和最后一个元素。这些方法返回一个 Option<T> 类型,如果链表不为空且成功删除元素,则返回 Some(element),否则返回 None

#![allow(unused)]
fn main() {
list.pop_front(); // 删除并返回第一个元素
list.pop_back(); // 删除并返回最后一个元素
}

5. 遍历元素:

可以使用 iter() 方法遍历链表中的所有元素。iter_mut() 方法可用于遍历可变引用。

#![allow(unused)]
fn main() {
for element in list.iter() {
    println!("{}", element);
}
}

6. 链表长度:

可以使用 len() 方法获取链表中的元素数量。还可以使用 is_empty() 方法检查链表是否为空。

7. 清空链表:

可以使用 clear() 方法删除链表中的所有元素。

#![allow(unused)]
fn main() {
list.clear(); // 清空链表
}

8. 分割链表:

可以使用 split_off() 方法在指定索引处分割链表。此操作会将链表分成两个链表,前一个链表包含指定索引之前的元素,后一个链表包含指定索引及之后的元素。

#![allow(unused)]
fn main() {
let mut list1 = LinkedList::new();
list1.push_back(1);
list1.push_back(2);
list1.push_back(3);

let list2 = list1.split_off(1);
}

这样,list1 将包含元素 1,而 list2 将包含元素 2 和 3。

总之,Rust 中的 LinkedList 提供了一种基于节点的线性数据结构,它适用于需要快速插入和删除操作的场景。然而,对于许多其他用途,如随机访问和查找操作,链表通常比数组或向量(Vector)等基于连续内存的数据结构性能差。这是因为链表的元素在内存中是分散存储的,这会导致较差的缓存局部性(cache locality)。而连续内存数据结构在许多情况下可以更有效地利用 CPU 缓存,从而提高性能。

当考虑使用链表时,务必评估其适用性,并与其他数据结构(如 Vector)进行比较。在某些情况下,链表可能是一个很好的选择,特别是当插入和删除操作的性能比访问和查找操作更重要时。然而,在许多场景中,使用基于连续内存的数据结构会带来更好的性能和更简单的代码。