我如何改变VecDeque?

时间:2016-12-18 13:15:32

标签: rust shuffle deque

我可以像这样简单地改变常规矢量:

extern crate rand;
use rand::Rng;

fn shuffle(coll: &mut Vec<i32>) {
    rand::thread_rng().shuffle(coll);
}

问题是,我的代码现在需要使用std::collections::VecDeque,这导致此代码无法编译。

最简单的解决方法是什么?

3 个答案:

答案 0 :(得分:6)

不幸的是,rand::Rng::shuffle method被定义为随机播放切片。由于其自身的复杂性约束,VecDeque无法将其元素存储在切片中,因此永远不能在shuffle上直接调用VecDeque

values算法对shuffle算法的实际要求是有限序列长度,O(1)元素访问,以及交换元素的能力,所有这些VecDeque都满足。如果有一个特征包含这些特征会很好,所以values可以是通用的,但是没有。

使用当前库,您有两个选择:

  • 使用Vec::from(deque)VecDeque复制到临时Vec,随机播放该向量,然后将内容返回VecDeque。这种操作的复杂性将保持为O(n),但它需要临时矢量的潜在大型和昂贵的堆分配。

  • 自己在VecDeque上实施随机播放。 rand::Rng使用的Fisher-Yates shuffle已被很好地理解并且易于实现,以其现代形式归结为仅约5 lines of code。虽然理论上标准库可以切换到不同的混洗算法,但实际上不太可能发生。

第二个选项的通用形式,使用特征来表达len-and-swap要求,并采用rand::Rng::shuffle的代码,可能如下所示:

extern crate rand;

use std::collections::VecDeque;

// Real requirement for shuffle
trait LenAndSwap {
    fn len(&self) -> usize;
    fn swap(&mut self, i: usize, j: usize);
}

// An exact copy of rand::Rng::shuffle, with the signature modified to
// accept any type that implements LenAndSwap
fn shuffle<T, R>(values: &mut T, mut rng: R)
    where T: LenAndSwap,
          R: rand::Rng {
    let mut i = values.len();
    while i >= 2 {
        // invariant: elements with index >= i have been locked in place.
        i -= 1;
        // lock element i in place.
        values.swap(i, rng.gen_range(0, i + 1));
    }
}

// VecDeque trivially fulfills the LenAndSwap requirement, but
// we have to spell it out.
impl<T> LenAndSwap for VecDeque<T> {
    fn len(&self) -> usize {
        self.len()
    }
    fn swap(&mut self, i: usize, j: usize) {
        self.swap(i, j)
    }
}

fn main() {
    let mut v: VecDeque<u64> = [1, 2, 3, 4].iter().cloned().collect();
    shuffle(&mut v, rand::thread_rng());
    println!("{:?}", v);
}

答案 1 :(得分:0)

您可以使用 make_contiguous (documentation) 创建一个可变切片,然后您可以对其进行随机播放:

use rand::prelude::*;
use std::collections::VecDeque;

fn main() {
    let mut deque = VecDeque::new();
    for p in 0..10 {
        deque.push_back(p);
    }
    deque.make_contiguous().shuffle(&mut rand::thread_rng());
    println!("Random deque: {:?}", deque)
}

Playground Link 如果您想在线试用。

答案 2 :(得分:-1)

VecDeque.html::as_mut_slices开始单独随机播放VecDeque的组件:

use rand::seq::SliceRandom; // 0.6.5;
use std::collections::VecDeque; 

fn shuffle(coll: &mut VecDeque<i32>) {
    let mut rng = rand::thread_rng();
    let (a, b) = coll.as_mut_slices();
    a.shuffle(&mut rng);
    b.shuffle(&mut rng);
}

作为Lukas Kalbertodt points out,此解决方案永远不会在两个切片之间交换元素,因此不会发生一定量的随机化。根据您的随机化需求,这可能是不明显的或交易破坏者。