【发布时间】:2020-06-10 23:44:43
【问题描述】:
我在下面的答案中发布了我的解决方案。
问题不会用更多代码更新,以免进一步增加混乱。
我正在尝试顺时针旋转Vec<Vec<T>> 中的所有元素。
向量保证为正方形,如v.len() == v[0].len()。
这个想法是
- 找到所有在旋转对称下等效的元素
v的中心 - 使用 std::mem::swap 交换这些元素
我当前的代码不会改变 vec 的状态。我该如何解决这个问题?
fn rotate<T>(v: &mut Vec<Vec<T>>) {
// swap elements equivalent to position i on each ring r
// limit l = side length of current ring
//
// + 0 - - - - + r = 0 -> l = 6
// | + 1 - - + | r = 1 -> l = 4
// | | + 2 + | | r = 2 -> l = 2
// | | | | | |
// | | + - + | | swap:
// | + - - - + | a b c d
// + - - - - - + > b a c d
// > c a b d
// > d a b c
for r in 0..((v.len() + 1) / 2 {
let l = v.len() - 1 - r;
for i in r..l {
let mut a = & pieces[ r ][ r+i ];
let mut b = & pieces[ r+i ][ l-r ];
let mut c = & pieces[ l-r ][l-r-i];
let mut d = & pieces[l-r-i][ r ];
_rot_cw(&mut a, &mut b, &mut c, &mut d)},
}
}
fn _rot_cw<T>(a: &mut T, b: &mut T, c: &mut T, d: &mut T) {
//rotates a->b, b->c, c->d, d->a
std::mem::swap(a, b);
std::mem::swap(a, c);
std::mem::swap(a, d);
}
}
编辑:
感谢@Jmb,修复了上面原始代码中的小问题。
这是我当前的代码,再次遇到借用问题:
fn rotate_square_slice<T>(slice: &mut Vec<T>, rows: usize) {
for r in 0..(slice.len()+1)/2 {
let l = slice.len() -1 - r;
for i in r..l {
let a = &mut slice.get_mut(rows * r + r+i ).unwrap();
let b = &mut slice.get_mut(rows * (r+i) + l-r ).unwrap();
let c = &mut slice.get_mut(rows * (l-r) + l-r-i).unwrap();
let d = &mut slice.get_mut(rows * (l-r-i) + r ).unwrap();
std::mem::swap(a, b);
std::mem::swap(a, c);
std::mem::swap(a, d);
}
}
}
【问题讨论】:
-
请不要为您使用的标识符添加前缀
_。这表明标识符必须存在但未使用该值,这对于您的_rot_cw而言并非如此。 -
& pieces您正在对向量中的项目进行 不可变 引用。由于它是不可变的,因此向量不会发生变异。 -
@Shepmaster 内部函数还有另一个成语吗?或者它们通常没有被标记,因为它们没有被暴露?
-
我有两个旁注。首先,将方阵表示为
Vec<Vec<_>>并不理想。此类型表示可变长度向量的可变长度向量,您必须手动维护每个内部向量与外部向量具有相同长度的不变量。此外,还有相当多的开销,因为您需要为每一行单独分配,并且元素访问需要多个指针间接。使用包装单个向量的自定义类型可以为您提供更好的类型安全性和更好的性能。 -
第二,如果将方阵实现为自定义类型,就会有自定义索引操作。这允许您为矩阵的两个轴引入两个strides,以及一些固定偏移量。然后,旋转矩阵变成了修改步幅和固定偏移量的问题,而不是实际移动所有数据。我不知道你的确切用例,所以我不知道这是否适合你,但这是一种在实践中证明有用的常用方法。