简体   繁体   中英

Rust reverse Linked List

I want to build palindrome checker in Rust, the constraint is O(n) time with 0(1) additional space. My ideas are:

  1. Get the middle of the linked list.
  2. Reverse the second half of the linked list.
  3. Check if the first half and second half are identical.
fn isListPalindrome(l: ListNode<i32>) -> bool {
    let mut fastPointer = &l;
    let mut slowPointer = &l;
    let mut midIndex = 0;

    // here first step
    loop {
        match fastPointer {
            Some(n) => {
                if let Some(nn) = &n.next {
                    fastPointer = &nn.next;
                } else {
                    break;
                }
                midIndex += 1;
            }
            None => break,
        }
        match slowPointer {
            Some(n) => slowPointer = &n.next,
            None => break,
        }
    }

    if let Some(_fp) = &fastPointer {
        slowPointer = &fastPointer;
    }

    // here is second step to reverse list
    let mut prev = None;
    while let Some(n) = slowPointer {
        let next = &n.next;
        n.next = prev.take();
        println!("{:?}", n);
        prev = &n;
        slowPointer = next;
    }

    true
}

The problem occured when I want to try reverse the second half linked list. The compile show error in the code prev = &n;
the error is:

note: expected reference &std::option::Option<std::boxed::Box<List<i32>>> found reference &&std::boxed::Box<List<i32>>

How to reverse list in second half of linked list for palindrome checker above?

You've got quite a lot of problems in your code, it doesn't look like you have a very good idea of what types you want each variable to be. When you declare let mut prev = None; , you've made it an owned value ( Option<T> for some T ), but then you assign to it prev = &n , which makes it &T for some T . There is no overlap between the type of an owned value and a borrowed value, so those two lines by themselves conflict with one another. I've created an implementation of a reverse algorithm below, and I tried to keep the type definitions as similar to yours as possible. It would have been helpful if you had included them in your question.

use std::mem::swap;

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

type ListNode = Option<Box<List>>;

fn reverse(head: &mut ListNode) {
    let tail = &mut None;
    while head.is_some() {
        swap(&mut head.as_mut().unwrap().next, tail);
        swap(head, tail);
    }
    swap(head, tail);
}

fn main() {
    let mut list = Some(Box::new(List {
        val: 0,
        next: Some(Box::new(List {
            val: 1,
            next: Some(Box::new(List {
                val: 2,
                next: Some(Box::new(List {
                    val: 3,
                    next: None,
                })),
            })),
        })),
    }));
    println!("{:?}", list);
    reverse(&mut list);
    println!("{:?}", list);
}

The way the algorithm works is that each iteration, it turns

head=(H1, H2...), tail=(T...) into

head=(H2...), tail=(H1, T...)

by first swapping H2... with T... , and then swapping head and tail . This ends up with head eventually being empty, and tail containing the reversed list. One final swap is then made so that head contains the list.

If you want to debug your own code, the first step would be to make sure you understand the difference between T , &T , and &mut T . T is an owned value, which means that it will be freed at the end of its scope. &T is a immutable reference to it, which is like a pointer in C, except you can't modify the value it points to. You can have as many of these as you want, but you can't do anything with the owned value until the borrow ends. &mut T is a mutable borrow of T , which is again like a pointer, but this time it will let you modify the location it points to. You can have one of these at a time. In the context of a linked list, you need to think about which types each variable should have, because you can't put a &mut T or a &T as the next in a list, you can only put an owned value there. You can get an owned value by using take() , swap() , replace() , etc. I could be misunderstanding your code and you might be trying something different, but you almost definitely won't want any immutable borrows ( &T ) in your reverse algorithm.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM