如何使用两个指针在Rust中迭代链表?

如何使用两个指针在Rust中迭代链表?,rust,Rust,我刚开始学习Rust lang,并尝试在Leetcode上进行一些练习。我正在解决这个问题 解决方法就是使用慢速和快速指针。这是我在Rust中的代码: #[derive(PartialEq, Eq, Debug)] pub struct ListNode { pub val: i32, pub next: Option<Box<ListNode>> } impl ListNode { #[inline] pub fn new(val: i

我刚开始学习Rust lang,并尝试在Leetcode上进行一些练习。我正在解决这个问题

解决方法就是使用慢速和快速指针。这是我在Rust中的代码:

#[derive(PartialEq, Eq, Debug)]
pub struct ListNode {
    pub val: i32,
    pub next: Option<Box<ListNode>>
}

impl ListNode {
    #[inline]
    pub fn new(val: i32) -> Self {
        ListNode {
            next: None,
            val
        }
    }
}

struct Solution;
impl Solution {
    pub fn middle_node(head: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
        let slow = &head;
        let fast = &head;
        while fast.is_some() && fast.unwrap().next.is_some() {
            slow = &(slow.unwrap().next);
            fast = &(fast.unwrap().next.unwrap().next);
        }
        *slow
    }
}
我知道我违反了借款人检查规则,即我不能从不可变的ref中取出某些内容,但是我应该如何实现这个双指针实现呢


任何建议都会有帮助,提前谢谢。

你的问题是你试图从借来的物品中搬出一些东西,这是完全正确的。首先,让我们看一下你的签名。
pub fn middle_node(head: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
没有所有权易手。没有所有权需要易手;调用方将在开始时拥有列表,在结束时拥有列表

现在,您分配给
fast
slow
,因此它们需要是可变的。您不能重新分配到普通的
let

let mut slow = head;
let mut fast = head;
(我还删除了
&head
,因为
head
现在已经是一个引用,所以我们不再需要引用了)

最后,正如您所说,您每次都试图将该值移出该选项,这对借阅检查器来说既不必要又容易混淆。幸运的是,
选项
提供了一种方便的方法来获取对内部的引用
as_ref
采用了一个
选项
并将其转换为
选项
,因此我们可以借用内部。我们需要在每次
展开之前将
作为\u ref
。比如说,

while fast.is_some() && fast.as_ref().unwrap().next.is_some() {
(请注意
作为_ref
)以及
展开
的所有其他位置的可选值。最后,返回的
*slow
变为
slow
,因为
slow
已经是一个引用,我们现在返回一个引用

可运行代码:

#[derive(PartialEq, Eq, Debug)]
pub struct ListNode {
    pub val: i32,
    pub next: Option<Box<ListNode>>
}

impl ListNode {
    #[inline]
    pub fn new(val: i32) -> Self {
        ListNode {
            next: None,
            val
        }
    }
}

struct Solution;
impl Solution {
    pub fn middle_node(head: &Option<Box<ListNode>>) -> &Option<Box<ListNode>> {
        let mut slow = head;
        let mut fast = head;
        while fast.is_some() && fast.as_ref().unwrap().next.is_some() {
            slow = &(slow.as_ref().unwrap().next);
            fast = &(fast.as_ref().unwrap().next.as_ref().unwrap().next);
        }
        slow
    }
}

fn arr_to_list(arr: &[i32]) -> Option<Box<ListNode>> {
    let mut head = None;
    for n in arr {
        let mut new_node = ListNode::new(*n);
        new_node.next = head;
        head = Some(Box::new(new_node));
    }
    head
}

fn main() {
    let node = arr_to_list(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
    let mid = Solution::middle_node(&node);
    println!("Middle node is {}", mid.as_ref().unwrap().val)
}
#[派生(PartialEq、Eq、Debug)]
发布结构列表节点{
发布日期:i32,
下一步:选项
}
impl列表节点{
#[内联]
新发布(val:i32)->Self{
列表节点{
下一个:没有,
瓦尔
}
}
}
结构解决方案;
impl解决方案{
发布fn中间节点(标题:&选项)->&选项{
让mut slow=head;
让mut fast=head;
while fast.is_some()&&fast.as_ref().unwrap().next.is_some(){
slow=&(slow.as_ref().unwrap().next);
fast=&(fast.as_ref().unwrap().next.as_ref().unwrap().next);
}
缓慢的
}
}
fn排列到排列列表(排列:&[i32])->选项{
让mut head=None;
对于arr中的n{
让mut new_node=ListNode::new(*n);
new_node.next=头部;
head=Some(Box::new(new_节点));
}
头
}
fn main(){
让node=arr_to_list(&[1,2,3,4,5,6,7,8,9,10]);
让mid=解决方案::middle_节点(&node);
println!(“中间节点是{}”,mid.as_ref().unwrap().val)
}

你好,西尔维奥,非常感谢你的回答。我认为方法签名middle_node(head:&Option)->&Option是由Leetcode定义的,我可能应该向他们报告这个错误。而且,看起来像Option。由于_ref().unwrap()是一个常用场景,我想知道为什么我们没有一个方法在核心库中将它们组合在一起。谢谢。根据我的经验,
unwrap
通常是不受欢迎的,除非是在这样的小程序中
选项
有很多其他的窥视方式,不涉及恐慌(
展开_或
确定_或
,等等),所有这些都需要与_ref
调用相同的
来确保借用。我同意你的观点,如果他们真的为该函数定义了自己的类型签名,应该向Leetcode报告这一点。他们可能只是针对所有的挑战这么做,而没有真正考虑它(如果你正在编写一个应该支持多种语言的挑战,那么这很容易做到),并且应该引起他们的注意。
while fast.is_some() && fast.as_ref().unwrap().next.is_some() {
#[derive(PartialEq, Eq, Debug)]
pub struct ListNode {
    pub val: i32,
    pub next: Option<Box<ListNode>>
}

impl ListNode {
    #[inline]
    pub fn new(val: i32) -> Self {
        ListNode {
            next: None,
            val
        }
    }
}

struct Solution;
impl Solution {
    pub fn middle_node(head: &Option<Box<ListNode>>) -> &Option<Box<ListNode>> {
        let mut slow = head;
        let mut fast = head;
        while fast.is_some() && fast.as_ref().unwrap().next.is_some() {
            slow = &(slow.as_ref().unwrap().next);
            fast = &(fast.as_ref().unwrap().next.as_ref().unwrap().next);
        }
        slow
    }
}

fn arr_to_list(arr: &[i32]) -> Option<Box<ListNode>> {
    let mut head = None;
    for n in arr {
        let mut new_node = ListNode::new(*n);
        new_node.next = head;
        head = Some(Box::new(new_node));
    }
    head
}

fn main() {
    let node = arr_to_list(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
    let mid = Solution::middle_node(&node);
    println!("Middle node is {}", mid.as_ref().unwrap().val)
}