diff options
| author | blake2-ppc <blake2-ppc> | 2013-09-09 01:29:07 +0200 |
|---|---|---|
| committer | blake2-ppc <blake2-ppc> | 2013-09-10 05:50:06 +0200 |
| commit | de9546a3f8c3153983a7b6069a9f2aee28f2e296 (patch) | |
| tree | e47a777ac41654cc0ba72c3c754e3f911e84ad3c /src/libstd | |
| parent | 6212729315be2ac80785ffcecfe0a80c9955c4cf (diff) | |
| download | rust-de9546a3f8c3153983a7b6069a9f2aee28f2e296.tar.gz rust-de9546a3f8c3153983a7b6069a9f2aee28f2e296.zip | |
std::vec: Replace each_permutation with a new Permutations iterator
Introduce ElementSwaps and Permutations. ElementSwaps is an iterator
that for a given sequence length yields the element swaps needed
to visit each possible permutation of the sequence in turn.
We use an algorithm that generates a sequence such that each permutation
is only one swap apart.
let mut v = [1, 2, 3];
for perm in v.permutations_iter() {
// yields 1 2 3 | 1 3 2 | 3 1 2 | 3 2 1 | 2 3 1 | 2 1 3
}
The `.permutations_iter()` yields clones of the input vector for each
permutation.
If a copyless traversal is needed, it can be constructed with
`ElementSwaps`:
for (a, b) in ElementSwaps::new(3) {
// yields (2, 1), (1, 0), (2, 1) ...
v.swap(a, b);
// ..
}
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/vec.rs | 284 |
1 files changed, 165 insertions, 119 deletions
diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 10a0bf27836..0a453d13714 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -408,56 +408,106 @@ pub fn unzip<T, U, V: Iterator<(T, U)>>(mut iter: V) -> (~[T], ~[U]) { (ts, us) } -/** - * Iterate over all permutations of vector `v`. - * - * Permutations are produced in lexicographic order with respect to the order - * of elements in `v` (so if `v` is sorted then the permutations are - * lexicographically sorted). - * - * The total number of permutations produced is `v.len()!`. If `v` contains - * repeated elements, then some permutations are repeated. - * - * See [Algorithms to generate - * permutations](http://en.wikipedia.org/wiki/Permutation). - * - * # Arguments - * - * * `values` - A vector of values from which the permutations are - * chosen - * - * * `fun` - The function to iterate over the combinations - */ -pub fn each_permutation<T:Clone>(values: &[T], fun: &fn(perm : &[T]) -> bool) -> bool { - let length = values.len(); - let mut permutation = vec::from_fn(length, |i| values[i].clone()); - if length <= 1 { - fun(permutation); - return true; - } - let mut indices = vec::from_fn(length, |i| i); - loop { - if !fun(permutation) { return true; } - // find largest k such that indices[k] < indices[k+1] - // if no such k exists, all permutations have been generated - let mut k = length - 2; - while k > 0 && indices[k] >= indices[k+1] { - k -= 1; - } - if k == 0 && indices[0] > indices[1] { return true; } - // find largest l such that indices[k] < indices[l] - // k+1 is guaranteed to be such - let mut l = length - 1; - while indices[k] >= indices[l] { - l -= 1; - } - // swap indices[k] and indices[l]; sort indices[k+1..] - // (they're just reversed) - indices.swap(k, l); - indices.mut_slice(k+1, length).reverse(); - // fixup permutation based on indices - for i in range(k, length) { - permutation[i] = values[indices[i]].clone(); +/// An Iterator that yields the element swaps needed to produce +/// a sequence of all possible permutations for an indexed sequence of +/// elements. Each permutation is only a single swap apart. +/// +/// The Steinhaus–Johnson–Trotter algorithm is used. +/// +/// Generates even and odd permutations alternatingly. +/// +/// The last generated swap is always (0, 1), and it returns the +/// sequence to its initial order. +pub struct ElementSwaps { + priv sdir: ~[SizeDirection], + /// If true, emit the last swap that returns the sequence to initial state + priv emit_reset: bool, +} + +impl ElementSwaps { + /// Create an `ElementSwaps` iterator for a sequence of `length` elements + pub fn new(length: uint) -> ElementSwaps { + // Initialize `sdir` with a direction that position should move in + // (all negative at the beginning) and the `size` of the + // element (equal to the original index). + ElementSwaps{ + emit_reset: true, + sdir: range(0, length) + .map(|i| SizeDirection{ size: i, dir: Neg }) + .to_owned_vec() + } + } +} + +enum Direction { Pos, Neg } + +/// An Index and Direction together +struct SizeDirection { + size: uint, + dir: Direction, +} + +impl Iterator<(uint, uint)> for ElementSwaps { + #[inline] + fn next(&mut self) -> Option<(uint, uint)> { + fn new_pos(i: uint, s: Direction) -> uint { + i + match s { Pos => 1, Neg => -1 } + } + + // Find the index of the largest mobile element: + // The direction should point into the vector, and the + // swap should be with a smaller `size` element. + let max = self.sdir.iter().map(|&x| x).enumerate() + .filter(|&(i, sd)| + new_pos(i, sd.dir) < self.sdir.len() && + self.sdir[new_pos(i, sd.dir)].size < sd.size) + .max_by(|&(_, sd)| sd.size); + match max { + Some((i, sd)) => { + let j = new_pos(i, sd.dir); + self.sdir.swap(i, j); + + // Swap the direction of each larger SizeDirection + for x in self.sdir.mut_iter() { + if x.size > sd.size { + x.dir = match x.dir { Pos => Neg, Neg => Pos }; + } + } + Some((i, j)) + }, + None => if self.emit_reset && self.sdir.len() > 1 { + self.emit_reset = false; + Some((0, 1)) + } else { + None + } + } + } +} + +/// An Iterator that uses `ElementSwaps` to iterate through +/// all possible permutations of a vector. +/// +/// The first iteration yields a clone of the vector as it is, +/// then each successive element is the vector with one +/// swap applied. +/// +/// Generates even and odd permutations alternatingly. +pub struct Permutations<T> { + priv swaps: ElementSwaps, + priv v: ~[T], +} + +impl<T: Clone> Iterator<~[T]> for Permutations<T> { + #[inline] + fn next(&mut self) -> Option<~[T]> { + match self.swaps.next() { + None => None, + Some((a, b)) => { + let elt = self.v.clone(); + self.v.swap(a, b); + Some(elt) + } } } } @@ -1141,6 +1191,7 @@ impl<'self, T: TotalOrd> ImmutableTotalOrdVector<T> for &'self [T] { pub trait ImmutableCopyableVector<T> { fn partitioned(&self, f: &fn(&T) -> bool) -> (~[T], ~[T]); unsafe fn unsafe_get(&self, elem: uint) -> T; + fn permutations_iter(self) -> Permutations<T>; } /// Extension methods for vectors @@ -1170,6 +1221,16 @@ impl<'self,T:Clone> ImmutableCopyableVector<T> for &'self [T] { unsafe fn unsafe_get(&self, index: uint) -> T { (*self.unsafe_ref(index)).clone() } + + /// Create an iterator that yields every possible permutation of the + /// vector in succession. + fn permutations_iter(self) -> Permutations<T> { + Permutations{ + swaps: ElementSwaps::new(self.len()), + v: self.to_owned(), + } + } + } #[allow(missing_doc)] @@ -2848,28 +2909,6 @@ mod tests { } #[test] - fn test_each_permutation() { - let mut results: ~[~[int]]; - - results = ~[]; - do each_permutation([]) |v| { results.push(v.to_owned()); true }; - assert_eq!(results, ~[~[]]); - - results = ~[]; - do each_permutation([7]) |v| { results.push(v.to_owned()); true }; - assert_eq!(results, ~[~[7]]); - - results = ~[]; - do each_permutation([1,1]) |v| { results.push(v.to_owned()); true }; - assert_eq!(results, ~[~[1,1],~[1,1]]); - - results = ~[]; - do each_permutation([5,2,0]) |v| { results.push(v.to_owned()); true }; - assert!(results == - ~[~[5,2,0],~[5,0,2],~[2,5,0],~[2,0,5],~[0,5,2],~[0,2,5]]); - } - - #[test] fn test_zip_unzip() { let z1 = ~[(1, 4), (2, 5), (3, 6)]; @@ -2881,6 +2920,58 @@ mod tests { } #[test] + fn test_element_swaps() { + let mut v = [1, 2, 3]; + for (i, (a, b)) in ElementSwaps::new(v.len()).enumerate() { + v.swap(a, b); + match i { + 0 => assert_eq!(v, [1, 3, 2]), + 1 => assert_eq!(v, [3, 1, 2]), + 2 => assert_eq!(v, [3, 2, 1]), + 3 => assert_eq!(v, [2, 3, 1]), + 4 => assert_eq!(v, [2, 1, 3]), + 5 => assert_eq!(v, [1, 2, 3]), + _ => fail!(), + } + } + } + + #[test] + fn test_permutations() { + use hashmap; + { + let v: [int, ..0] = []; + let mut it = v.permutations_iter(); + assert_eq!(it.next(), None); + } + { + let v = [~"Hello"]; + let mut it = v.permutations_iter(); + assert_eq!(it.next(), None); + } + { + let v = [1, 2, 3]; + let mut it = v.permutations_iter(); + assert_eq!(it.next(), Some(~[1,2,3])); + assert_eq!(it.next(), Some(~[1,3,2])); + assert_eq!(it.next(), Some(~[3,1,2])); + assert_eq!(it.next(), Some(~[3,2,1])); + assert_eq!(it.next(), Some(~[2,3,1])); + assert_eq!(it.next(), Some(~[2,1,3])); + assert_eq!(it.next(), None); + } + { + // check that we have N! unique permutations + let mut set = hashmap::HashSet::new(); + let v = ['A', 'B', 'C', 'D', 'E', 'F']; + for perm in v.permutations_iter() { + set.insert(perm); + } + assert_eq!(set.len(), 2 * 3 * 4 * 5 * 6); + } + } + + #[test] fn test_position_elem() { assert!([].position_elem(&1).is_none()); @@ -3175,13 +3266,12 @@ mod tests { fn test_permute_fail() { let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; let mut i = 0; - do each_permutation(v) |_elt| { + for _ in v.permutations_iter() { if i == 2 { fail!() } i += 1; - true - }; + } } #[test] @@ -3494,50 +3584,6 @@ mod tests { } #[test] - fn test_permutations0() { - let values = []; - let mut v : ~[~[int]] = ~[]; - do each_permutation(values) |p| { - v.push(p.to_owned()); - true - }; - assert_eq!(v, ~[~[]]); - } - - #[test] - fn test_permutations1() { - let values = [1]; - let mut v : ~[~[int]] = ~[]; - do each_permutation(values) |p| { - v.push(p.to_owned()); - true - }; - assert_eq!(v, ~[~[1]]); - } - - #[test] - fn test_permutations2() { - let values = [1,2]; - let mut v : ~[~[int]] = ~[]; - do each_permutation(values) |p| { - v.push(p.to_owned()); - true - }; - assert_eq!(v, ~[~[1,2],~[2,1]]); - } - - #[test] - fn test_permutations3() { - let values = [1,2,3]; - let mut v : ~[~[int]] = ~[]; - do each_permutation(values) |p| { - v.push(p.to_owned()); - true - }; - assert_eq!(v, ~[~[1,2,3],~[1,3,2],~[2,1,3],~[2,3,1],~[3,1,2],~[3,2,1]]); - } - - #[test] fn test_vec_zero() { use num::Zero; macro_rules! t ( |
