【发布时间】:2019-06-18 21:37:19
【问题描述】:
我已阅读有关旋转矩阵的堆栈溢出的所有问题 除了在单层或整个矩阵的任一方向上转置或旋转 90 或 180 度之外,它们都没有解决任何问题。
我已经回答了这个问题,但我正在寻找快速和/或“就地”的方法,最好是,但任何方法 除了我给的那个之外,如果只是为了 教育目的。我的示例是在 Perl 5 中,但只要您的意图明确,大多数任何语言都应该是可以接受的。
我的例子中使用的矩阵如下
# 2D array @arr has 3 layers.
# @arr is
# 0 1 2 3 4 5
# a b c d e f
# 5 4 3 2 1 0
# 9 8 7 6 5 4
# f e d c b a
# 4 5 6 7 8 9
Goal->顺时针旋转中间层2个位置得到以下...
请注意中间层的左上角“b c”如何向右移动了 2 个位置,而中间左侧的“8 4”现在是“b c”所在的位置。
# Rotated @arr is
# 0 1 2 3 4 5
# a 8 4 b c f
# 5 e 3 2 d 0
# 9 d 7 6 e 4
# f c b 5 1 a
# 4 5 6 7 8 9
目前我一直在按照这个思路做一些事情,诚然,这非常慢。尤其是在许多大型阵列上。
#!/usr/bin/env perl
use strict; use warnings;
# Coordinates are $arr[$row][$col]
my @arr;
$arr[0][0]='0'; $arr[0][1]='1'; $arr[0][2]='2'; $arr[0][3]='3'; $arr[0][4]='4'; $arr[0][5]='5';
$arr[1][0]='a'; $arr[1][1]='b'; $arr[1][2]='c'; $arr[1][3]='d'; $arr[1][4]='e'; $arr[1][5]='f';
$arr[2][0]='5'; $arr[2][1]='4'; $arr[2][2]='3'; $arr[2][3]='2'; $arr[2][4]='1'; $arr[2][5]='0';
$arr[3][0]='9'; $arr[3][1]='8'; $arr[3][2]='7'; $arr[3][3]='6'; $arr[3][4]='5'; $arr[3][5]='4';
$arr[4][0]='f'; $arr[4][1]='e'; $arr[4][2]='d'; $arr[4][3]='c'; $arr[4][4]='b'; $arr[4][5]='a';
$arr[5][0]='4'; $arr[5][1]='5'; $arr[5][2]='6'; $arr[5][3]='7'; $arr[5][4]='8'; $arr[5][5]='9';
# Print matrix
print_matrix(@arr);
# Extract layer 2
my $target_layer=2;
my $layer_two=extract_layer($target_layer,@arr);
# From the top left corner of the layer, it is as follows
# bcde15bcde84
print "\n$layer_two\n";
# Rotate layer 2 clockwise 2 places
$layer_two=rotate_layer_cl($layer_two,2);
# 84bcde15bcde
print "$layer_two\n\n";
# Replace layer 2 in the same way
@arr=replace_layer($target_layer,$layer_two,@arr);
# Print again
print_matrix(@arr);
### Sub functions ###
# Extract layer by walking around it's coordinates like so
# [1,1]-[1,4] Top(left->right)
# [2,4]-[4,4] Right(top->bottom)
# [4,3]-[4,1] Bottom(right->left)
# [3,1]-[2,1] Left(bottom->top)
sub extract_layer {
my ($layer_cnt,@matrix)=@_;
my $width=scalar(@matrix);
my $layer_width=$width-$layer_cnt;
# layer_cnt=2
# width=6
# layer_width=4
my $layer;
for my $col ( $layer_cnt-1..$layer_width ) {
$layer.=$matrix[$layer_cnt-1][$col];
}
for my $row ( $layer_cnt..$layer_width ) {
$layer.=$matrix[$row][$layer_width];
}
my $cnt=$layer_width-1;
while ( $cnt >= $layer_cnt-1 ) {
$layer.=$matrix[$layer_width][$cnt];
$cnt--;
}
$cnt=$layer_width-1;
while ( $cnt >= $layer_cnt ) {
$layer.=$matrix[$cnt][$layer_cnt-1];
$cnt--;
}
return $layer;
}
# Shift input to the right by $n places, wrapping around.
sub rotate_layer_cl {
my $n=$_[1];
my $buf=substr($_[0],length($_[0])-$n,$n);
return $buf.substr($_[0],0,length($_[0])-$n);
}
# Replace each char from the rotated layer.
sub replace_layer {
my ($layer_cnt,$layer,@matrix)=@_;
my $width=scalar(@matrix);
my $layer_width=$width-$layer_cnt;
# layer_cnt=2
# width=6
# layer_width=4
my $slot=0;
for my $col ( $layer_cnt-1..$layer_width ) {
$matrix[$layer_cnt-1][$col]=substr($layer,$slot,1);
$slot++;
}
for my $row ( $layer_cnt..$layer_width ) {
$matrix[$row][$layer_width]=substr($layer,$slot,1);
$slot++;
}
my $cnt=$layer_width-1;
while ( $cnt >= $layer_cnt-1 ) {
$matrix[$layer_width][$cnt]=substr($layer,$slot,1);
$slot++;
$cnt--;
}
$cnt=$layer_width-1;
while ( $cnt >= $layer_cnt ) {
$matrix[$cnt][$layer_cnt-1]=substr($layer,$slot,1);
$slot++;
$cnt--;
}
return @matrix;
}
# Prints given matrix
sub print_matrix {
foreach my $row (@_) {
my $cnt=0;
foreach my $char (@$row) {
print $char; $cnt++;
if ( $cnt == scalar(@_) ) {
print "\n";
} else {
print " ";
}
}
}
}
以上代码输出如下,
0 1 2 3 4 5
a b c d e f
5 4 3 2 1 0
9 8 7 6 5 4
f e d c b a
4 5 6 7 8 9
bcde15bcde84
84bcde15bcde
0 1 2 3 4 5
a 8 4 b c f
5 e 3 2 d 0
9 d 7 6 e 4
f c b 5 1 a
4 5 6 7 8 9
其中显示了旋转中间层之前的数组,中间层为字符串,中间层移位为字符串,中间层向右旋转 2 位后的最终结果数组。
-----编辑-----
到目前为止,我发现最快的方法是不实际使用完整的二维数组,而是将块放入常规数组中,例如...
my @hex_ary=('1234', '5678', '90ab', 'cdef');
然后创建图层字符串并按照我原始示例显示的方式移动它。
但是,因为它们是字符串,我只需要在两侧“走”上和下。顶部和底部被简单地引用为...
my $top=substr($hex_ary[0],0,3);
和
my $bot=reverse(substr($hex_ary[3],0,3));
对于这个小 4x4 数组中的外层,而边是迭代的
my $right_side_char=substr($hex_ary[$top_row-$i],-1);
my $left_side_char=substr($hex_ary[$bot_row+$i],0,1);
这样做可以提高性能大约。 100% 来自 2D 方法,因为从数组中取出的切片数是 half+2。
也许对 C 有更好理解的人可以创造出更高效的东西。我觉得 Perl 有时只能做这么多。
【问题讨论】:
-
一个想法:你能不能把旋转表达为一个函数
f(x,y),即输入(x,y)是中间层每个成员的行/列索引,输出是旋转位置@987654331 @?。那么方法是(1)制作@arr的副本,(2)循环中间层成员并根据f()的输出将每个成员放在副本中。 -
我猜你还需要一个函数
members(ring_identifier),它返回一个数组,其中包含环ring_identifier的所有成员的[x,y]条目。这将是for my($x, $y) (@{ $members }) { ... }循环的来源。 -
我在想这样的事情,但不完全确定如何实现它。非常感谢。
-
很高兴我们能提供帮助,我非常喜欢在这方面工作。请记住对答案进行投票并接受您最喜欢的答案。
标签: arrays perl matrix multidimensional-array 2d