双重单链表

我们纠结于双向链接列表,因为它们具有复杂的所有权语义: 没有一个节点严格地拥有任何其他节点。然而我们在这个问题上挣扎,因为我们带来了关于链表是什么的先入为主的观念。也就是说,我们假设所有的链接都朝着同一个方向。

相反,我们可以把列表分成两部分: 一部分在左边,另一部分在右边:

// lib.rs
// ...
pub mod silly1;     // NEW!
// silly1.rs
use second::List as Stack;

struct List<T> {
    left: Stack<T>,
    right: Stack<T>,
}

现在,我们有了一个通用列表,而不是仅仅拥有安全的堆栈。 我们可以通过压入任一堆栈来向左或向右增加列表。 我们还可以通过将值从一端弹出到另一端来“遍历”列表。 为了避免不必要的分配,我们将复制安全堆栈的源以访问其私有详细信息:

pub struct Stack<T> {
    head: Link<T>,
}

type Link<T> = Option<Box<Node<T>>>;

struct Node<T> {
    elem: T,
    next: Link<T>,
}

impl<T> Stack<T> {
    pub fn new() -> Self {
        Stack { head: None }
    }

    pub fn push(&mut self, elem: T) {
        let new_node = Box::new(Node {
            elem: elem,
            next: self.head.take(),
        });

        self.head = Some(new_node);
    }

    pub fn pop(&mut self) -> Option<T> {
        self.head.take().map(|node| {
            let node = *node;
            self.head = node.next;
            node.elem
        })
    }

    pub fn peek(&self) -> Option<&T> {
        self.head.as_ref().map(|node| {
            &node.elem
        })
    }

    pub fn peek_mut(&mut self) -> Option<&mut T> {
        self.head.as_mut().map(|node| {
            &mut node.elem
        })
    }
}

impl<T> Drop for Stack<T> {
    fn drop(&mut self) {
        let mut cur_link = self.head.take();
        while let Some(mut boxed_node) = cur_link {
            cur_link = boxed_node.next.take();
        }
    }
}

只需在 push 和 pop 上修改一点:

现在我们可以列出我们的 list:

我们可以做一些平常的事情:

但最有趣的是,我们可以四处遍历!

我们在这里返回布尔值只是为了方便起见,以表明我们是否确实设法移动了。 现在让我们测试一下这个婴儿:

这是一个指针数据结构的极端例子,我们在结构中保持某种指针,因此可以支持在与指针距离成正比的时间位置上的操作。

我们可以用指针很快地改变列表,但是如果我们想要改变的远离我们的手指,我们就必须一直走到那里。我们可以通过将元素从一个堆栈移动到另一个堆栈来永久地移动到那里,或者我们可以只是使用 &mut 临时地沿着链接移动来进行更改。但是 &mut 永远不能回到列表中,而我们的指针可以!

Last updated

Was this helpful?