about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-05-16 20:04:41 -0700
committerbors <bors@rust-lang.org>2013-05-16 20:04:41 -0700
commit77c98f081509733af957af6ed7b0b277e5f57871 (patch)
treeb22d79763ac3aed77ddc1ac412c3d9dff6523a87
parent09bf401f1d4f843ead4d4fe955348ce5e8215fb1 (diff)
parentaf54d58891505a67aaab5365b957679b0c593eb7 (diff)
auto merge of #6523 : cmr/rust/faster_each_permutation, r=luqmana
Closes #5127
-rw-r--r--src/libcore/vec.rs147
1 files changed, 127 insertions, 20 deletions
diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs
index 9db3585e03a..4c6e0791ba2 100644
--- a/src/libcore/vec.rs
+++ b/src/libcore/vec.rs
@@ -1445,6 +1445,46 @@ pub fn reverse<T>(v: &mut [T]) {
     }
 }
 
+/**
+ * Reverse part of a vector in place.
+ *
+ * Reverse the elements in the vector between `start` and `end - 1`.
+ *
+ * If either start or end do not represent valid positions in the vector, the
+ * vector is returned unchanged.
+ *
+ * # Arguments
+ *
+ * * `v` - The mutable vector to be modified
+ *
+ * * `start` - Index of the first element of the slice
+ *
+ * * `end` - Index one past the final element to be reversed.
+ *
+ * # Example
+ *
+ * Assume a mutable vector `v` contains `[1,2,3,4,5]`. After the call:
+ *
+ * ~~~
+ *
+ * reverse_part(v, 1, 4);
+ *
+ * ~~~
+ *
+ * `v` now contains `[1,4,3,2,5]`.
+ */
+pub fn reverse_part<T>(v: &mut [T], start: uint, end : uint) {
+    let sz = v.len();
+    if start >= sz || end > sz { return; }
+    let mut i = start;
+    let mut j = end - 1;
+    while i < j {
+        vec::swap(v, i, j);
+        i += 1;
+        j -= 1;
+    }
+}
+
 /// Returns a vector with the order of elements reversed
 pub fn reversed<T:Copy>(v: &const [T]) -> ~[T] {
     let mut rs: ~[T] = ~[];
@@ -1739,29 +1779,49 @@ pub fn each2_mut<U, T>(v1: &mut [U], v2: &mut [T], f: &fn(u: &mut U, t: &mut T)
  *
  * The total number of permutations produced is `len(v)!`.  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
  */
-#[cfg(not(stage0))]
-pub fn each_permutation<T:Copy>(v: &[T], put: &fn(ts: &[T]) -> bool) -> bool {
-    let ln = len(v);
-    if ln <= 1 {
-        put(v);
-    } else {
-        // This does not seem like the most efficient implementation.  You
-        // could make far fewer copies if you put your mind to it.
-        let mut i = 0u;
-        while i < ln {
-            let elt = v[i];
-            let mut rest = slice(v, 0u, i).to_vec();
-            rest.push_all(const_slice(v, i+1u, ln));
-            for each_permutation(rest) |permutation| {
-                if !put(append(~[elt], permutation)) {
-                    return false;
-                }
-            }
-            i += 1u;
+pub fn each_permutation<T:Copy>(values: &[T], fun: &fn(perm : &[T]) -> bool) -> bool {
+    let length = values.len();
+    let mut permutation = vec::from_fn(length, |i| values[i]);
+    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)
+        vec::swap(indices, k, l);
+        reverse_part(indices, k+1, length);
+        // fixup permutation based on indices
+        for uint::range(k, length) |i| {
+            permutation[i] = values[indices[i]];
         }
     }
-    return true;
 }
 
 /**
@@ -4731,6 +4791,53 @@ mod tests {
     }
 
     #[test]
+    fn test_reverse_part() {
+        let mut values = [1,2,3,4,5];
+        reverse_part(values,1,4);
+        assert_eq!(values, [1,4,3,2,5]);
+    }
+
+    #[test]
+    fn test_permutations0() {
+        let values = [];
+        let mut v : ~[~[int]] = ~[];
+        for each_permutation(values) |p| {
+            v.push(p.to_owned());
+        }
+        assert_eq!(v, ~[~[]]);
+    }
+
+    #[test]
+    fn test_permutations1() {
+        let values = [1];
+        let mut v : ~[~[int]] = ~[];
+        for each_permutation(values) |p| {
+            v.push(p.to_owned());
+        }
+        assert_eq!(v, ~[~[1]]);
+    }
+
+    #[test]
+    fn test_permutations2() {
+        let values = [1,2];
+        let mut v : ~[~[int]] = ~[];
+        for each_permutation(values) |p| {
+            v.push(p.to_owned());
+        }
+        assert_eq!(v, ~[~[1,2],~[2,1]]);
+    }
+
+    #[test]
+    fn test_permutations3() {
+        let values = [1,2,3];
+        let mut v : ~[~[int]] = ~[];
+        for each_permutation(values) |p| {
+            v.push(p.to_owned());
+        }
+        assert_eq!(v, ~[~[1,2,3],~[1,3,2],~[2,1,3],~[2,3,1],~[3,1,2],~[3,2,1]]);
+    }
+
+    #[test]
     fn test_each_val() {
         use old_iter::CopyableNonstrictIter;
         let mut i = 0;