一、认识幻方

        说到幻方,很多人可能还不知道什么是幻方。幻方是一种将一些连续的正整数安排在正方形格子中,使每行、列和对角线上的数字和都相等的方法。因为正方形格子可能是3*3或者n*n的,所以幻方就有了几阶幻方的说法。需要注意的是幻方最低是3阶!

                                   java基础算法——n阶幻方的实现                            java基础算法——n阶幻方的实现

                                       三阶幻方                                              四阶幻方

二、n阶幻方实现

        在网上参考了现有的求解幻方的算法,将幻方进行了分类:奇数阶幻方、单偶阶幻方、双偶阶幻方。接下来使用java来实现这三种幻方的求法。

      奇数阶幻方

       一、 奇数阶幻方我采用了最简单的罗伯法:

            1、将最小的数放在第一行最中间

            2、然后依次将下一个数放在上一个数的右上方

            3、如果下一个数超出了上边界则放在下边界,纵坐标不变;超出了右边界则放在左边界,横坐标不变

            4、如果下一个数的位置已经存放了数,则将下一个数放在上一个数的下方

       二、思考如何将算法转换成代码

            1、如何存放幻方(即如何将存放数字的排列)

                 数组作为一种常用的存储数据的引用类型,其下标还可以很好的方便我们对幻方里的值进行查询和修改,所以使用int类型的二维数组存储幻方中的数字。

                 int[][]  arr=new  int[len][len];//len是幻方的阶数

            2、如何记录上一个数与当前数的坐标

                arr数组的下标即可以记录数字的下标。我们将一系列连续的数存放在数组中肯定会使用到for循环,那么完全可以使用两个int值x,y来记录上个数的下标,然后根据罗伯法对x,y的值进行修改得到正确的当前数的下标

        三、代码填充

            1、定义二位数组,长度为幻方阶数

                 int[][]  arr=new  int[len][len];//len是幻方的阶数

            2、将最小的数num存放在第一行正中间,同时记录该数的坐标

                arr[0][len/2]=num;

                int x=0;int y=len/2;

            3、使用for循环存放数字

                for(int i=num+1;i<len*len+num;i++){}

                 ps:接下来的代码都将在这个for循环里面

            4、确定当前数的坐标

                理想状态下当前数的坐标是x-1,y+1。如果x-1越界,则直接将x赋值为len-1即下边界;同理,如果y+1越界则直接将y赋值为0即左边界。

                如果当前数的坐标已经存放了数字,则找到上一个数的坐标(大家可以自己写出二位数组中查询某个数下标的方法,此处使用getIndex(int[][] arr,int num这个方法来表示))然后行数加1,注意此处仍然需要注意x是否越界。同时此处得到的新的坐标也有可能存在数字,所以可以放在while循环里。

                if(x-1<0){
x=arr.length-1;//x越界
}else{
x=x-1;
}
if(y+1>arr.length-1){
y=0;//y越界
}else{
y=y+1;
}
while(true){
    if(arr[x][y]==0){//当前坐标数组没有存放数字,直接存放
    arr[x][y]=i;
    break;
    }else{//当前坐标数组存放数字,需要获取上个数的坐标
    int[] js = getIndex(arr, i-1);
    x=js[0]+1;//使当前数的坐标变成上个数的下面的坐标
    y=js[1];
    if(x>arr.length-1){
x=0;

    }

                    }

}

        四、代码测试

            java基础算法——n阶幻方的实现

            经测试可以看到,代码可以正确实现奇数阶幻方

            双偶阶幻方

        一、双偶阶幻方我使用了对称交换法:

                1、首先将数字按从小到大的顺序依次放入正方格中
                2、先沿着正方格的一条对角线,将他左半边的值与其右半边的值进行交换。另一条对角线操作类似
                java基础算法——n阶幻方的实现

         二、代码实现

                因为逻辑相对简单,所以省去中间环节,直接进行代码填充
                1、定义数组
                int[][]  arr=new int [len][len];//len为数组长度
                2、将数字从小到大依次存入
                int a=1;
for(int i=0;i<len;i++){
for(int j=0;j<len;j++){
arr[i][j]=a;
a++;
}
}
                3、交换对角线的值
                for(int i=0;i<len/2;i++){
                        //交换\方向的对角线左半部和右半部的值,其坐标关于len/2,len/2对称
int num=arr[i][i];
arr[i][i]=arr[len-1-i][len-1-i];
arr[len-1-i][len-1-i]=num;
                        //交换/方向的对角线左半部和右半部的值,其坐标关于len/2,len/2对称
num=arr[i][len-1-i];
arr[i][len-1-i]=arr[len-1-i][i];
arr[len-1-i][i]=num;
}

        三、代码测试

           java基础算法——n阶幻方的实现
             经测试可以看到,代码可以正确实现双偶阶幻方

            单偶阶幻方

        一、单偶阶幻方使用了象限对称交换法

                1、先创建4个长宽只有一半的正方格,即len/2
                2、把数字从小到大依次放入这四个正方格中
                3、对这四个正方格使用奇数阶幻方求法
                4、将这四个正方格放到原来的正方格中,数字最小的格子放在左上角,最大的放在左下角,第二大的放在右上角,第三大的放在右下角
                java基础算法——n阶幻方的实现
            5、n=len/2,将左上角正中间的数及他右边n-1个数与左下角对应的数交换;将左上角其他行最左边的n个数与左下角对应的数交换
            6、将右上角中间一列开始从左向右共n-1列与右下角交换

        二、填充代码

            1、定义四个长度为len/2的二位数组,同时使用奇数阶幻方求法
            int[][] is1 = getSingleArray(len/2,1);
    int[][] is2 = getSingleArray(len/2,1+len*len/4);
    int[][] is3 = getSingleArray(len/2,1+2*len*len/4);
    int[][] is4 = getSingleArray(len/2,1+3*len*len/4);
            2、将四个数组按要求放在一个len长度的二维数组中
            for(int i=0;i<len;i++){
    for(int j=0;j<len;j++){
if(i<len/2&&j<len/2){//左上角
arr[i][j]=is1[i][j];
}else if(i>=len/2&&j>=len/2){//右下角
arr[i][j]=is2[i-len/2][j-len/2];
}else if(i<len/2&&j>=len/2){//右上角
arr[i][j]=is3[i][j-len/2];
}else{//左下角
        arr[i][j]=is4[i-len/2][j];
}
}
}
            3、将左上角和右上角的数按照需要与左下角和右下角交换
            for(int i=0;i<len/2;i++){
if(i==len/4){
for(int j=0;j<len/4;j++){//左上角正中间开始向右len/4个与左下角对应的坐标交换值
int s=arr[i][i+j];
arr[i][i+j]=arr[i+len/2][i+j];
arr[i+len/2][i+j]=s;
}
                        }else{//左上角左边开始向右len/4个与左下角对应的坐标交换值
for(int j=0;j<len/4;j++){
int s=arr[i][j];
arr[i][j]=arr[i+len/2][j];
arr[i+len/2][j]=s;
}
}
if(len/4-1!=0){
for(int j=len/2+len/4;j<len-2;j++){//右上角中间一列及其右侧len/4-2列与右下角对应的坐标交换值
  for(int k=0;k<len/2;k++){
int s=arr[k][j];
arr[k][j]=arr[k+len/2][j];
arr[k+len/2][j]=s;
}
}
}
}
}

        三、代码测试

        java基础算法——n阶幻方的实现
        经测试可以看到,代码可以正确实现单偶阶幻方

三、心得体会

        作为一个开始学习java几个月的菜鸟,当老师给出这道问题时很感兴趣。通过在网上查阅很多大佬的算法有了一个大概想法。由于网上并没有代码参考,所以决定将自己的想法过程发布出来。可能写的依然不是很清楚,大家可以在评论里一起讨论,谢谢!
ps:java代码链接:https://download.csdn.net/download/kingmipple/10379957

相关文章: