Skip to content

Commit 3f5ab0f

Browse files
committed
Add Permutation::permute_in_place
This method (as the name implies) permutes the target slice in-place with constant space rather than allocating a clone. The trade-off is worse asymptotic running time for large permutations with large cycles -- O(n^2) worst-case, but O(n log n) expected since most permutations don't have large cycles.
1 parent bc925ef commit 3f5ab0f

1 file changed

Lines changed: 45 additions & 0 deletions

File tree

src/permutation.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,24 @@ impl Permutation {
8888
.map(|i| v[self.apply(i)].clone())
8989
.collect::<Vec<_>>()
9090
}
91+
/// Permutes a slice in-place with this permutation.
92+
pub fn permute_in_place<T>(&self, target: &mut [T]) {
93+
assert_eq!(self.len(), target.len());
94+
95+
// Swap length - 1 times, because by the time we get to the last element it must already be
96+
// in place.
97+
for source_index in 0..(self.len() - 1) {
98+
let mut dest_index = dbg!(self.apply(source_index));
99+
100+
// If the destination index is less than the source index then we've already swapped
101+
// that element. Apply the permutation again to find where it was swapped to.
102+
while dest_index < dbg!(source_index) {
103+
dest_index = dbg!(self.apply(dest_index));
104+
}
105+
106+
target.swap(source_index, dest_index);
107+
}
108+
}
91109
/// Returns the composition of the permutation with itself.
92110
pub fn square(&self) -> Permutation {
93111
self * self
@@ -299,6 +317,33 @@ mod tests {
299317
assert_eq!(vec!['a', 'c', 'b'], p.permute(&vec!['a', 'b', 'c']));
300318
}
301319

320+
#[test]
321+
fn test_permute_in_place_identity() {
322+
let permutation = Permutation(Box::new([0, 1, 2, 3, 4]));
323+
let mut target = ['a', 'b', 'c', 'd', 'e'];
324+
permutation.permute_in_place(&mut target);
325+
326+
assert_eq!(['a', 'b', 'c', 'd', 'e'], target);
327+
}
328+
329+
#[test]
330+
fn test_permute_in_place_reversed() {
331+
let permutation = Permutation(Box::new([4, 3, 2, 1, 0]));
332+
let mut target = ['a', 'b', 'c', 'd', 'e'];
333+
permutation.permute_in_place(&mut target);
334+
335+
assert_eq!(['e', 'd', 'c', 'b', 'a'], target);
336+
}
337+
338+
#[test]
339+
fn test_permute_in_place_cycle() {
340+
let permutation = Permutation(Box::new([1, 2, 3, 4, 0]));
341+
let mut target = ['a', 'b', 'c', 'd', 'e'];
342+
permutation.permute_in_place(&mut target);
343+
344+
assert_eq!(['b', 'c', 'd', 'e', 'a'], target);
345+
}
346+
302347
#[test]
303348
fn test_square() {
304349
let p = Permutation::rotation_left(3, 1);

0 commit comments

Comments
 (0)