about summary refs log tree commit diff
diff options
context:
space:
mode:
authorThomas Backman <serenity@exscape.org>2014-06-03 16:11:47 +0200
committerThomas Backman <serenity@exscape.org>2014-06-03 16:11:47 +0200
commit3b5d6fd25486b29a70adfda6cb917ced614bc6d2 (patch)
treea0ddcc7a971f62d52d07bad9170eec327714fcb5
parent918dbfea60e84868537a1951ad38a782502d39c2 (diff)
downloadrust-3b5d6fd25486b29a70adfda6cb917ced614bc6d2.tar.gz
rust-3b5d6fd25486b29a70adfda6cb917ced614bc6d2.zip
Add next_permutation and prev_permutation onto MutableOrdVector<T>.
Unlike ImmutableClonableVector::permutations() which returns an iterator,
cloning the entire array each iteration, these methods mutate the vector in-place.
For that reason, these methods are much faster; between 35-55 times faster,
depending on the benchmark. They also generate permutations in lexicographical order.
-rw-r--r--src/libstd/slice.rs142
1 files changed, 142 insertions, 0 deletions
diff --git a/src/libstd/slice.rs b/src/libstd/slice.rs
index 5753663dd87..8f66279a9a3 100644
--- a/src/libstd/slice.rs
+++ b/src/libstd/slice.rs
@@ -712,6 +712,36 @@ pub trait MutableOrdVector<T> {
     /// assert!(v == [-5, -3, 1, 2, 4]);
     /// ```
     fn sort(self);
+
+    /// Mutates the slice to the next lexicographic permutation.
+    ///
+    /// Returns `true` if successful, `false` if the slice is at the last-ordered permutation.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// let v = &mut [0, 1, 2];
+    /// v.next_permutation();
+    /// assert_eq!(v, &mut [0, 2, 1]);
+    /// v.next_permutation();
+    /// assert_eq!(v, &mut [1, 0, 2]);
+    /// ```
+    fn next_permutation(self) -> bool;
+
+    /// Mutates the slice to the previous lexicographic permutation.
+    ///
+    /// Returns `true` if successful, `false` if the slice is at the first-ordered permutation.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// let v = &mut [1, 0, 2];
+    /// v.prev_permutation();
+    /// assert_eq!(v, &mut [0, 2, 1]);
+    /// v.prev_permutation();
+    /// assert_eq!(v, &mut [0, 1, 2]);
+    /// ```
+    fn prev_permutation(self) -> bool;
 }
 
 impl<'a, T: Ord> MutableOrdVector<T> for &'a mut [T] {
@@ -719,6 +749,66 @@ impl<'a, T: Ord> MutableOrdVector<T> for &'a mut [T] {
     fn sort(self) {
         self.sort_by(|a,b| a.cmp(b))
     }
+
+    fn next_permutation(self) -> bool {
+        // These cases only have 1 permutation each, so we can't do anything.
+        if self.len() < 2 { return false; }
+
+        // Step 1: Identify the longest, rightmost weakly decreasing part of the vector
+        let mut i = self.len() - 1;
+        while i > 0 && self[i-1] >= self[i] {
+            i -= 1;
+        }
+
+        // If that is the entire vector, this is the last-ordered permutation.
+        if i == 0 {
+            return false;
+        }
+
+        // Step 2: Find the rightmost element larger than the pivot (i-1)
+        let mut j = self.len() - 1;
+        while j >= i && self[j] <= self[i-1]  {
+            j -= 1;
+        }
+
+        // Step 3: Swap that element with the pivot
+        self.swap(j, i-1);
+
+        // Step 4: Reverse the (previously) weakly decreasing part
+        self.mut_slice_from(i).reverse();
+
+        true
+    }
+
+    fn prev_permutation(self) -> bool {
+        // These cases only have 1 permutation each, so we can't do anything.
+        if self.len() < 2 { return false; }
+
+        // Step 1: Identify the longest, rightmost weakly increasing part of the vector
+        let mut i = self.len() - 1;
+        while i > 0 && self[i-1] <= self[i] {
+            i -= 1;
+        }
+
+        // If that is the entire vector, this is the first-ordered permutation.
+        if i == 0 {
+            return false;
+        }
+
+        // Step 2: Reverse the weakly increasing part
+        self.mut_slice_from(i).reverse();
+
+        // Step 3: Find the rightmost element equal to or bigger than the pivot (i-1)
+        let mut j = self.len() - 1;
+        while j >= i && self[j-1] < self[i-1]  {
+            j -= 1;
+        }
+
+        // Step 4: Swap that element with the pivot
+        self.swap(i-1, j);
+
+        true
+    }
 }
 
 /// Unsafe operations
@@ -1230,6 +1320,58 @@ mod tests {
     }
 
     #[test]
+    fn test_lexicographic_permutations() {
+        let v : &mut[int] = &mut[1, 2, 3, 4, 5];
+        assert!(v.prev_permutation() == false);
+        assert!(v.next_permutation());
+        assert_eq!(v, &mut[1, 2, 3, 5, 4]);
+        assert!(v.prev_permutation());
+        assert_eq!(v, &mut[1, 2, 3, 4, 5]);
+        assert!(v.next_permutation());
+        assert!(v.next_permutation());
+        assert_eq!(v, &mut[1, 2, 4, 3, 5]);
+        assert!(v.next_permutation());
+        assert_eq!(v, &mut[1, 2, 4, 5, 3]);
+
+        let v : &mut[int] = &mut[1, 0, 0, 0];
+        assert!(v.next_permutation() == false);
+        assert!(v.prev_permutation());
+        assert_eq!(v, &mut[0, 1, 0, 0]);
+        assert!(v.prev_permutation());
+        assert_eq!(v, &mut[0, 0, 1, 0]);
+        assert!(v.prev_permutation());
+        assert_eq!(v, &mut[0, 0, 0, 1]);
+        assert!(v.prev_permutation() == false);
+    }
+
+    #[test]
+    fn test_lexicographic_permutations_empty_and_short() {
+        let empty : &mut[int] = &mut[];
+        assert!(empty.next_permutation() == false);
+        assert_eq!(empty, &mut[]);
+        assert!(empty.prev_permutation() == false);
+        assert_eq!(empty, &mut[]);
+
+        let one_elem : &mut[int] = &mut[4];
+        assert!(one_elem.prev_permutation() == false);
+        assert_eq!(one_elem, &mut[4]);
+        assert!(one_elem.next_permutation() == false);
+        assert_eq!(one_elem, &mut[4]);
+
+        let two_elem : &mut[int] = &mut[1, 2];
+        assert!(two_elem.prev_permutation() == false);
+        assert_eq!(two_elem, &mut[1, 2]);
+        assert!(two_elem.next_permutation());
+        assert_eq!(two_elem, &mut[2, 1]);
+        assert!(two_elem.next_permutation() == false);
+        assert_eq!(two_elem, &mut[2, 1]);
+        assert!(two_elem.prev_permutation());
+        assert_eq!(two_elem, &mut[1, 2]);
+        assert!(two_elem.prev_permutation() == false);
+        assert_eq!(two_elem, &mut[1, 2]);
+    }
+
+    #[test]
     fn test_position_elem() {
         assert!([].position_elem(&1).is_none());