如何反转单链表并将其转换为向量?

How to reverse a singly-linked list and convert it to a vector?

在写A*算法的时候,我尝试将一个单向动作链表逆向打包成Vec

这是我的单链表的结构:

use std::rc::Rc;

struct FrontierElem<A> {
    prev: Option<Rc<FrontierElem<A>>>,
    action: A,
}

我的第一个想法是将 push 动作转换为 Vec 然后反转向量:

fn rev1<A>(fel: &Rc<FrontierElem<A>>) -> Vec<A>
where
    A: Clone,
{
    let mut cur = fel;
    let mut ret = Vec::new();
    while let Some(ref prev) = cur.prev {
        ret.push(cur.action.clone());
        cur = prev;
    } // First action (where cur.prev==None) is ignored by design
    ret.as_mut_slice().reverse();
    ret
}

当时没找到SliceExt::reverse的方法,于是进行第二个方案:从尾到头填充vector。我没有找到安全的方法。

/// Copies action fields from single-linked list to vector in reverse order.
/// `fel` stands for first element
fn rev2<A>(fel: &Rc<FrontierElem<A>>) -> Vec<A>
where
    A: Clone,
{
    let mut cnt = 0usize;
    // First pass. Let's find a length of list `fel`
    {
        let mut cur = fel;
        while let Some(ref prev) = cur.prev {
            cnt = cnt + 1;
            cur = prev;
        }
    } // Lexical scoping to unborrow `fel`

    // Second pass. Create and fill `ret` vector
    let mut ret = Vec::<A>::with_capacity(cnt);
    {
        let mut idx = cnt - 1;
        let mut cur = fel;
        // I didn't find safe and fast way to populate vector from the end to the beginning.
        unsafe {
            ret.set_len(cnt); //unsafe. vector values aren't initialized
            while let Some(ref prev) = cur.prev {
                ret[idx] = cur.action.clone();
                idx = idx - 1;
                cur = prev;
            }
        }
        assert_eq!(idx, std::usize::MAX);
    } // Lexical scoping to make `fel` usable again
    ret
}

在写这篇文章的时候,我突然想到我也可以为链表实现Iterator,然后使用revfrom_iter来创建一个向量。 las,这需要大量开销,因为我必须实现 DoubleEndedIterator 特性才能使 rev 工作。

在这一点上我的问题似乎微不足道,但我post希望它会有一些用处。

基准:

running 2 tests
test bench_rev1 ... bench:   1537061 ns/iter (+/- 14466)
test bench_rev2 ... bench:   1556088 ns/iter (+/- 17165)

填充向量,然后使用 .as_mut_slice().reverse().

反转它
fn rev1<A>(fel: &Rc<FrontierElem<A>>) -> Vec<A>
where
    A: Clone,
{
    let mut cur = fel;
    let mut ret = Vec::new();
    while let Some(ref prev) = cur.prev {
        ret.push(cur.action.clone());
        cur = prev;
    } // First action (where cur.prev==None) is ignored by design
    ret.as_mut_slice().reverse();
    ret
}