双单向链表
在之前的双向链表章节中,我们一度非常纠结,原因来自同样纠结成一团的所有权依赖。还有一个重要原因就是:先入为主的链表定义。
谁说所有的链接一定要一个方向呢?这里一起来尝试下新的东东:链表的其中一半朝左,另一半朝右。
新规矩( 老规矩是创建文件 ),创建一个新的模块:
#![allow(unused)] fn main() { // lib.rs // ... pub mod silly1; // NEW! }
#![allow(unused)] fn main() { // silly1.rs use crate::second::List as Stack; struct List<T> { left: Stack<T>, right: Stack<T>, } }
这里将之前的 List
引入进来,并重命名为 Stack
,接着,创建一个新的链表。现在既可以向左增长又可以向右增长。
#![allow(unused)] fn main() { 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
:
#![allow(unused)] fn main() { pub fn push(&mut self, elem: T) { let new_node = Box::new(Node { elem: elem, next: None, }); self.push_node(new_node); } fn push_node(&mut self, mut node: Box<Node<T>>) { node.next = self.head.take(); self.head = Some(node); } pub fn pop(&mut self) -> Option<T> { self.pop_node().map(|node| { node.elem }) } fn pop_node(&mut self) -> Option<Box<Node<T>>> { self.head.take().map(|mut node| { self.head = node.next.take(); node }) } }
现在可以开始构造新的链表:
#![allow(unused)] fn main() { pub struct List<T> { left: Stack<T>, right: Stack<T>, } impl<T> List<T> { fn new() -> Self { List { left: Stack::new(), right: Stack::new() } } } }
当然,还有一大堆左左右右类型的操作:
#![allow(unused)] fn main() { pub fn push_left(&mut self, elem: T) { self.left.push(elem) } pub fn push_right(&mut self, elem: T) { self.right.push(elem) } pub fn pop_left(&mut self) -> Option<T> { self.left.pop() } pub fn pop_right(&mut self) -> Option<T> { self.right.pop() } pub fn peek_left(&self) -> Option<&T> { self.left.peek() } pub fn peek_right(&self) -> Option<&T> { self.right.peek() } pub fn peek_left_mut(&mut self) -> Option<&mut T> { self.left.peek_mut() } pub fn peek_right_mut(&mut self) -> Option<&mut T> { self.right.peek_mut() } }
其中最有趣的是:还可以来回闲逛了。
#![allow(unused)] fn main() { pub fn go_left(&mut self) -> bool { self.left.pop_node().map(|node| { self.right.push_node(node); }).is_some() } pub fn go_right(&mut self) -> bool { self.right.pop_node().map(|node| { self.left.push_node(node); }).is_some() } }
这里返回 bool
是为了告诉调用者我们是否成功的移动。最后,再来测试下:
#![allow(unused)] fn main() { #[cfg(test)] mod test { use super::List; #[test] fn walk_aboot() { let mut list = List::new(); // [_] list.push_left(0); // [0,_] list.push_right(1); // [0, _, 1] assert_eq!(list.peek_left(), Some(&0)); assert_eq!(list.peek_right(), Some(&1)); list.push_left(2); // [0, 2, _, 1] list.push_left(3); // [0, 2, 3, _, 1] list.push_right(4); // [0, 2, 3, _, 4, 1] while list.go_left() {} // [_, 0, 2, 3, 4, 1] assert_eq!(list.pop_left(), None); assert_eq!(list.pop_right(), Some(0)); // [_, 2, 3, 4, 1] assert_eq!(list.pop_right(), Some(2)); // [_, 3, 4, 1] list.push_left(5); // [5, _, 3, 4, 1] assert_eq!(list.pop_right(), Some(3)); // [5, _, 4, 1] assert_eq!(list.pop_left(), Some(5)); // [_, 4, 1] assert_eq!(list.pop_right(), Some(4)); // [_, 1] assert_eq!(list.pop_right(), Some(1)); // [_] assert_eq!(list.pop_right(), None); assert_eq!(list.pop_left(), None); } } }
$ cargo test
Running target/debug/lists-5c71138492ad4b4a
running 16 tests
test fifth::test::into_iter ... ok
test fifth::test::basics ... ok
test fifth::test::iter ... ok
test fifth::test::iter_mut ... ok
test fourth::test::into_iter ... ok
test fourth::test::basics ... ok
test fourth::test::peek ... ok
test first::test::basics ... ok
test second::test::into_iter ... ok
test second::test::basics ... ok
test second::test::iter ... ok
test second::test::iter_mut ... ok
test third::test::basics ... ok
test third::test::iter ... ok
test second::test::peek ... ok
test silly1::test::walk_aboot ... ok
test result: ok. 16 passed; 0 failed; 0 ignored; 0 measured
上上下下,左左右右,BABA,哦耶,这个链表无敌了!
以上是一个非常典型的手指型数据结构,在其中维护一个手指,然后操作所需的时间与手指的距离成正比。