From: Thomas Backman Date: Tue, 3 Jun 2014 14:11:47 +0000 (+0200) Subject: Add next_permutation and prev_permutation onto MutableOrdVector. X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=3b5d6fd25486b29a70adfda6cb917ced614bc6d2;p=rust.git Add next_permutation and prev_permutation onto MutableOrdVector. 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. --- 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 { /// 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 for &'a mut [T] { @@ -719,6 +749,66 @@ impl<'a, T: Ord> MutableOrdVector 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 @@ -1229,6 +1319,58 @@ fn test_permutations() { } } + #[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());