1. 案例提出
把前n2个正整数1,2,...,n2 从左上角开始,由外层至中心按顺时针方向螺旋排列所成的数字矩阵,称n阶顺转方阵;按逆时针方向螺旋排列所成的称n阶逆转方阵。
下面即为一个5阶顺转方阵
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
5阶顺转方阵2. 设计要点
设计以顺转展开,设置二维数组a[h][v]存放方阵中第h行第v列的整数。
把n阶方阵从外到内分圈,外圈内是一个n-2阶顺转方阵,只是起始数,具有与原问题相同的特性属性。
因此,设置旋转方阵递归函数t(a,b,s,d),其中a是存储方阵元素的数组;b为每个方阵的起始位置;d是为a数组赋值的整数;s是方阵的阶数。
b赋初值0, 因数组下标从0开始,方阵的起始位置为(0,0)。以后每一圈后进入下一内方阵,起始位置b需增1。
d从1开始递增1取值,分别赋值给数组的各元素,至n2 为止。
s从方阵的阶数n开始,以后每一圈后进入下一内方阵,s需减2。
s=0时返回,作为递归的出口;
s=1时,即方阵只有一个数,显然为a[b][b]=d,返回。
s>1时,在函数t(a,b,s,d)中还需调用t(a,b+1,s-2,d)。
递归函数t(a,b,s,d)中对方阵的每一圈的各边的各个元素赋值:
1) 一圈的上行从左至右递增
for(j=1;j<s;j++)
{a[h][v]=d;v++;d++;} // 行号h不变,列号v递增,数d递增
2) 一圈的右列从上至下递增
for(j=1;j<s;j++)
{a[h][v]=d;h++;d++;} // 列号v不变,行号v递增,数d递增
3) 一圈的下行从右至左递增
for(j=1;j<s;j++)
{a[h][v]=d;v--;d++;} // 行号h不变,列号v递减,数d递增
4) 一圈的左行从下至上递增
for(j=1;j<s;j++)
{a[h][v]=d;h--;d++;} // 列号v不变,行号h递减,数d递增
经以上4步,完成一圈的赋值。
主程序中,只要带实参调用递归函数t(a,0,n,1)即可。
3. 程序实现
package basic_practice;
import java.util.Scanner;
public class anlian_bfs {
static int a[][]=new int[20][20];//默认值为0
static void t(int a[][],int b,int s,int d){//a是存储方阵元素的数组,b为每个方阵的起始位置;d是为a数组赋值的整数;s是方阵的阶数
int j,h=b,v=b;
if(s==0) return; // 递归出口
if(s==1)
{ a[b][b]=d;return;}
for(j=1;j<s;j++) // 一圈的上行从左至右递增
{ a[h][v]=d;v++;d++;}
for(j=1;j<s;j++) // 一圈的右列从上至下递增
{ a[h][v]=d;h++;d++;}
for(j=1;j<s;j++) // 一圈的下行从右至左递增
{ a[h][v]=d;v--;d++;}
for(j=1;j<s;j++) // 一圈的左行从下至上递增
{ a[h][v]=d;h--;d++;}
t(a,b+1,s-2,d); // 调用内一圈递归函数
}
public static void main(String[] args) {
int h,v,b,p,s,d,n;
Scanner in=new Scanner(System.in);
n=in.nextInt();
b=1;s=n;d=1;
t(a,b,s,d);
for(h=1;h<=n;h++)
{ for(v=1;v<=n;v++)
System.out.print(a[h][v]+" ");
System.out.println();
}
}
}