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

时间:2019-01-03 18:18:05

标签: rust

我刚刚开始学习Rust lang,并尝试在Leetcode上进行一些练习。我正在解决问题Middle of the Linked List

解决方案只是使用慢速和快速指针。这是我在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
    }
}

但是,我遇到了很多编译器错误,例如:

  --> src/main.rs:22:33
   |
22 |         while fast.is_some() && fast.unwrap().next.is_some() {
   |                                 ^^^^ cannot move out of borrowed content

我了解我违反了借款人检查规则,无法从不可变的ref中删除某些内容,但是我应该如何实现这种两指针实现?

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

1 个答案:

答案 0 :(得分:2)

您说的很对,您的问题是您正试图将某些东西移出借用的对象。首先,让我们看一下您的签名。

pub fn middle_node(head: Option<Box<ListNode>>) -> Option<Box<ListNode>> {

此函数获取head的所有权并返回列表(列表的某些子列表)的所有权。无疑这不是您想要的,因为它会使对该列表的任何其他引用无效。在这种情况下,我们想借用该参数并返回另一个引用。

pub fn middle_node(head: &Option<Box<ListNode>>) -> &Option<Box<ListNode>> {

没有所有权易主。无需所有权就易手;呼叫者将首先拥有该列表,而最终将拥有该列表。

现在,您将分配给fastslow,因此它们必须是可变的。您无法将其重新分配给普通的let

let mut slow = head;
let mut fast = head;

(我还删除了&head,因为head现在已经是引用,所以我们不再需要引用了)

现在,最后,正如您所说,您正试图每次将从选项中移出,这既不必要又使借阅检查器感到困惑。幸运的是,Option提供了一种方便的方法来引用内部。 as_ref取一个Option<T>并将其变成Option<&T>,因此我们可以借用内部内容。每次as_ref之前,我们都需要unwrap。例如,

while fast.is_some() && fast.as_ref().unwrap().next.is_some() {

(请注意as_ref)并且在其他所有地方,您unwrap的可选内容都是相同的。最后,返回的*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)
}