Rust实现双向链表LinkedList
use std::fmt::{Display, Formatter};
use std::marker::PhantomData;
use std::ptr::{null, null_mut};
#[derive(Debug)]
struct Node<T> {
value: T,
// 每个节点使用next连接;下一个节点可能为空所以使用Option;
// 我们使用了裸指针指向节点,所以使用Box来获取节点的地址(如果不使用Box,获取的地址只是变量的地址,而不是Node<T>的地址)。
next: Option<Box<Node<T>>>,
// 使用裸指针指向上一个Node
pre: *mut Node<T>,
}
struct LinkedList<T> {
// 链表的头节点,这里不能使用裸指针,原因是链表需要持有所有Node的所有权,否则Node会被drop
head: Option<Box<Node<T>>>,
// 使用裸指针指向链表的尾节点
tail: *mut Node<T>,
// 链表长度
pub length: usize,
}
impl<T> LinkedList<T> {
// 获取尾节点的可变引用 (尾节点是裸指针,不便于直接使用,使用前需要转换为引用)
fn tail_mut(&mut self) -> Option<&mut Node<T>> {
mut_to_option_node(self.tail)
}
}
// 将节点引用转为裸指针
fn option_node_to_ptr<T>(option_node: &Option<Box<Node<T>>>) -> *const Node<T> {
option_node
.as_ref()
.map(|it| it.as_ref() as *const Node<T>)
.unwrap_or(null())
}
// 将节点引用转为可变裸指针
fn option_node_to_mut<T>(option_node: &mut Option<Box<Node<T>>>) -> *mut Node<T> {
option_node
.as_mut()
.map(|it| it.as_mut() as *mut Node<T>)
.unwrap_or(null_mut())
}
// 将可变裸指针转为可变引用
fn mut_to_option_node<'a, T>(ptr: *mut Node<T>) -> Option<&'a mut Node<T>> {
if ptr.is_null() {
None
} else {
Some(unsafe { &mut *ptr })
}
}
impl<T> LinkedList<T> {
fn new() -> Self {
Self {
head: None,
tail: null_mut(),
length: 0,
}
}
// 获取不可变引用迭代器
fn iter(&self) -> Iter<T> {
Iter {
cur: option_node_to_ptr(&self.head),
// 占位用的
_p: &PhantomData,
}
}
// 向链表头部添加元素
fn add_first(&mut self, v: T) {
// 创建一个Node, 需要用Box,因为后面要通过Box.as_ref()获取这个Node的地址
// 如果不使用Box,那么获取地址: &new_node as *mut Node<T>,这样只能拿到new_node这个变量的地址,而不是Node的地址
let mut new_node = Box::new(Node {
value: v,
next: None,
pre: null_mut(),
});
// 如果头节点不为空,旧头节点的pre指向新头节点
if let Some(head) = &mut self.head {
head.pre = new_node.as_mut() as *mut Node<T>;
} else {
// 链表是空的,链表尾节点指向这个新头节点
self.tail = new_node.as_mut() as *mut Node<T>;
}
// 新头节点的next指向旧头节点
new_node.next = self.head.take();
// 链表头节点指向新的头节点
self.head = Some(new_node);
self.length += 1;
}
// 向链表尾部添加元素
fn add_last(&mut self, v: T) {
let new_node = Box::new(Node {
value: v,
next: None,
// 新尾节点的pre指向旧的尾节点
pre: self.tail,
});
match self.tail_mut() {
// 如果链表是空的,向首尾添加元素都是一样的,这里使用已有的方法,添加第一个元素
None => self.add_first(new_node.value),
// 如果链表不为空
Some(node) => {
// 旧尾节点指向新尾节点
node.next = Some(new_node);
// 链表尾节点指向新的尾节点
self.tail = option_node_to_mut(&mut node.next);
self.length += 1;
}
}
}
// 移除第一个元素
fn remove_first(&mut self) -> Option<T> {
self.head.take().map(|mut it| {
// 头节点指向头节点的下一个节点, 旧的头节点被删除
self.head = it.next;
// 如果头节点是空,说明链表为空了
if self.head.is_none() {
// 链表的尾节点也置为空
self.tail = null_mut();
}
self.length -= 1;
// 返回被移出的值
it.value
})
}
// 移除最后一个元素
fn remove_last(&mut self) -> Option<T> {
// 如果尾节点为空,说明链表也是空
if self.tail.is_null() {
None
} else {
match mut_to_option_node(self.tail_mut().unwrap().pre) {
// 如果倒数第二个节点为空,说明只有一个元素了,直接使用remove_first移出最后一个元素
None => self.remove_first(),
// 如果倒数第二个节点不为空
Some(pre) => {
// 链表尾节点指向倒数第二个节点
self.tail = pre;
self.length -= 1;
// 删除并返回尾结点
return pre.next.take().map(|it| it.value);
}
}
}
}
}
// 迭代器
struct Iter<'a, T> {
// 指向当前遍历的节点
cur: *const Node<T>,
// 占位用的,因为必须要填一个引用生命周期
_p: &'a PhantomData<T>,
}
// 实现不可变引用迭代器 (可不可变引用迭代器同理,所有权迭代器更简单 剩下这两种迭代器可以参考这里的不可变引用迭代器)
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
if self.cur.is_null() {
// 如果当前元素为空了,直接返回空
None
} else {
// 获取当前元素的值
let v = &unsafe { &*self.cur }.value;
// 当前元素指向它的下一个元素
self.cur = option_node_to_ptr(&unsafe { &*self.cur }.next);
// 返回当前元素
Some(v)
}
}
}
// 实现Display,方便打印
impl<T: ToString> Display for LinkedList<T> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> std::fmt::Result {
let v = self
.iter()
.map(|it| it.to_string())
.reduce(|a, b| format!("{},{}", a, b))
.unwrap_or("".to_string());
writeln!(fmt, "[{}]", v)
}
}
#[cfg(test)]
mod test {
use crate::linked_list::LinkedList;
#[test]
fn test1() {
let mut list = LinkedList::new();
list.add_last(1);
list.add_last(2);
list.add_last(3);
list.add_last(4);
list.add_first(0);
list.add_first(-1);
list.add_last(5);
println!("{}", list);
assert_eq!(
list.iter().collect::<Vec<&i32>>(),
vec![-1, 0, 1, 2, 3, 4, 5].iter().collect::<Vec<&i32>>()
);
assert_eq!(list.length, 7);
}
#[test]
fn test2() {
let mut list = LinkedList::new();
list.add_first(1);
list.add_last(2);
list.add_first(0);
list.add_last(3);
list.add_last(4);
list.add_first(-1);
list.add_last(5);
println!("{}", list);
assert_eq!(
list.iter().collect::<Vec<&i32>>(),
vec![-1, 0, 1, 2, 3, 4, 5].iter().collect::<Vec<&i32>>()
);
assert_eq!(list.length, 7);
}
#[test]
fn test3() {
let mut list = LinkedList::new();
list.add_first(1);
list.add_last(2);
list.add_first(0);
assert_eq!(Some(2), list.remove_last());
assert_eq!(Some(1), list.remove_last());
assert_eq!(Some(0), list.remove_last());
assert_eq!(None, list.remove_last());
assert_eq!(list.length, 0);
}
#[test]
fn test4() {
let mut list = LinkedList::new();
list.add_first(1);
list.add_last(2);
list.add_first(0);
assert_eq!(Some(0), list.remove_first());
assert_eq!(Some(1), list.remove_first());
assert_eq!(Some(2), list.remove_first());
assert_eq!(None, list.remove_first());
assert_eq!(list.length, 0);
}
}