C语言实现魔方阵
问题描述
编写程序,实现如下表所示的5-魔方阵。17 | 24 | 1 | 8 | 15 |
23 | 5 | 7 | 14 | 16 |
4 | 6 | 13 | 20 | 22 |
10 | 12 | 19 | 21 | 3 |
11 | 18 | 25 | 2 | 9 |
5-魔方阵
问题分析
所谓“n-魔方阵”,指的是使用1〜n2共n2个自然数排列成一个n×n的方阵,其中n为奇数;该方阵的每行、每列及对角线元素之和都相等,并为一个只与n有关的常数,该常数为n×(n2+1)/2。例如5-魔方阵,其第一行、第一列及主对角线上各元素之和如下:
- 第一行元素之和:17+24+1+8+15=65
- 第一列元素之和:17+23+4+10+11=65
- 主对角线上元素之和:17+5+13+21+9=65
而 n×(n2+1)/2=5×(52+1)/2=65 可以验证,5-魔方阵中其余各行、各列及副对角线上的元素之和也都为65。
假定阵列的行列下标都从0开始,则魔方阵的生成方法为:在第0行中间置1,对从2开始的其余n2-1个数依次按下列规则存放:
(1) 假定当前数的下标为(i,j),则下一个数的放置位置为当前位置的右上方,即下标为(i-1,j+1)的位置。
(2) 如果当前数在第0行,即i-1小于0,则将下一个数放在最后一行的下一列上,即下标为(n-1,j+1)的位置。
(3) 如果当前数在最后一列上,即j+1大于n-1,则将下一个数放在上一行的第一列上,即下标为(i-1,0)的位置。
(4) 如果当前数是n的倍数,则将下一个数直接放在当前位置的正下方,即下标为(i+1,j)的位置。
算法设计
在设计算法时釆用了下面一些方法:- 定义array()函数,array()函数的根据输入的n值,生成并显示一个魔方阵,当发现n不是奇数时,就加1使之成为奇数。
- 使用动态内存分配与释放函数malloc()与free(),在程序执行过程中动态分配与释放内存,这样做的好处是使代码具有通用性,同时提高内存的使用率。
在分配内存时还要注意,由于一个整型数要占用两个内存,因此,如果魔方阵中要存放的数有max个,则分配内存时要分配2*max个单元,从而有malloc(max+max)。在malloc()函数中使用max+max而不是2*max是考虑了程序运行的性能。
显然应该使用二维数组来表示魔方阵,但虽然数组是二维形式的,而由于内存是一维线性的,因此在存取数组元素时,要将双下标转换为单个索引编号。在程序中直接定义了指针变量来指向数组空间,即使用malloc()函数分配的内存。
下面是完整的代码:
#include<stdio.h> #include<stdlib.h> int array(int n) { int i, j, no, num, max; int *mtrx; if(n%2 == 0) /*n是偶数,则加1使其变为奇数*/ { n=n+1; } max=n*n; mtrx=(int *)malloc(max+max); /*为魔方阵分配内存*/ mtrx[n/2]=1; /* 将1存入数组*/ i=0; /*自然数1所在行*/ j=n/2; /*自然数1所在列*/ /*从2开始确定每个数的存放位置*/ for(num=2; num<=max; num++) { i=i-1; j=j+1; if((num-1)%n == 0) /*当前数是n的倍数*/ { i=i+2; j=j-1; } if(i<0) /*当前数在第0行*/ { i=n-1; } if(j>n-1) /*当前数在最后一列,即n-1列*/ { j=0; } no=i*n+j; /*找到当前数在数组中的存放位置*/ mtrx[no]=num; } /*打印生成的魔方阵*/ printf("生成的%d-魔方阵为:",n); no=0; for(i=0; i<n; i++) { printf("\n"); for(j=0; j<n; j++) { printf("%3d", mtrx[no]); no++; } } printf("\n"); free(mtrx); return 0; } int main() { int n; printf("请输入n值:\n"); scanf("%d", &n); array(n); /*调用array函数*/ return 0; }运行结果:
请输入n值: 5↙︎ 生成的5-魔方阵为: 17 24 1 8 15 23 5 7 14 16 4 6 13 20 22 10 12 19 21 3 11 18 25 2 9
知识点补充
在解决该问题时,采用的是动态分配内存的方式,并使用了指针变量mtrx来指向二维数组中的元素。在算法设计中,要存储魔方阵需要一个二维数组,因此再给出直接使用二维数组来生成5-魔方阵的程序。直接使用二维数组生成5-魔方阵的代码如下:
#include<stdio.h> #define N 5 int main() { int a[N][N]={0}, i, j, k, t, x, y; i=0; /*自然数1的行标*/ j=N/2; /*自然数1的列标*/ t=N-1; /*最后一行、最后一列的下标*/ for(k=1; k<=N*N; k++) { a[i][j]=k; x=i; y=j; if(i == 0) i=t; else i=i-1; if(j != t) j=j+1; else j=0; if(a[i][j]!=0) { i=x+1; j=y; } } printf("生成的5-魔方阵为:"); for(i=0; i<N; i++) { printf("\n"); for(j=0; j<N; j++) { printf("%3d", a[i][j]); } } printf("\n"); return 0; }运行结果:
生成的5-魔方阵为: 17 24 1 8 15 23 5 7 14 16 4 6 13 20 22 10 12 19 21 3 11 18 25 2 9