Rust实现双向链表LinkedList

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);
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是用 Rust 实现双向链表的代码: ```rust use std::rc::Rc; use std::cell::RefCell; struct Node<T> { value: T, prev: Option<Rc<RefCell<Node<T>>>>, next: Option<Rc<RefCell<Node<T>>>>, } impl<T> Node<T> { fn new(value: T) -> Rc<RefCell<Self>> { Rc::new(RefCell::new(Node { value, prev: None, next: None, })) } } pub struct LinkedList<T> { head: Option<Rc<RefCell<Node<T>>>>, tail: Option<Rc<RefCell<Node<T>>>>, len: usize, } impl<T> LinkedList<T> { pub fn new() -> Self { LinkedList { head: None, tail: None, len: 0, } } pub fn push_front(&mut self, value: T) { let new_node = Node::new(value); match self.head.take() { Some(old_head) => { old_head.borrow_mut().prev = Some(new_node.clone()); new_node.borrow_mut().next = Some(old_head); self.head = Some(new_node); } None => { self.head = Some(new_node.clone()); self.tail = Some(new_node); } } self.len += 1; } pub fn push_back(&mut self, value: T) { let new_node = Node::new(value); match self.tail.take() { Some(old_tail) => { old_tail.borrow_mut().next = Some(new_node.clone()); new_node.borrow_mut().prev = Some(old_tail); self.tail = Some(new_node); } None => { self.head = Some(new_node.clone()); self.tail = Some(new_node); } } self.len += 1; } pub fn pop_front(&mut self) -> Option<T> { self.head.take().map(|old_head| { match old_head.borrow_mut().next.take() { Some(new_head) => { new_head.borrow_mut().prev = None; self.head = Some(new_head); } None => { self.tail = None; } } self.len -= 1; Rc::try_unwrap(old_head).ok().unwrap().into_inner().value }) } pub fn pop_back(&mut self) -> Option<T> { self.tail.take().map(|old_tail| { match old_tail.borrow_mut().prev.take() { Some(new_tail) => { new_tail.borrow_mut().next = None; self.tail = Some(new_tail); } None => { self.head = None; } } self.len -= 1; Rc::try_unwrap(old_tail).ok().unwrap().into_inner().value }) } pub fn len(&self) -> usize { self.len } } ``` 希望这个代码对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值