二维数组的声明
“数据类型 变量名[行数] [列数]”
eg:int a[4][4]
二维数组的使用
表示如上图的五角星所在格子
“变量名文字部分[变量横坐标] [变量纵坐标]”
eg:a[2][1]
例题
0.安排方阵
题目分析
题中已经给出了数组类型为整型,同时提到需要避免不够用的情况,由于计算机从0起计数,所以在考虑到不够用的情况下,应至少声明11*11大小的数组,推荐多开5个,则应为大小15 * 15。在声明好15 *15大小的二维数组后,二维数组内每个格子的值为随机值(野值),而不是0,在没有对这个二维数组初始化为0,即没有对所占用的内存空间初始化前,内存的值仍为上一个所占用此内存的任务所用的值,因此在初始化前,每个格子的值为随机(野值)
实操代码
#include<iostream>
using namespace std;
int main(){
int a[15][15]={};//在声明二维数组的同时,对其进行初始化为0
return 0;
}
1.清空场地
题目分析
根据题目,已知输入范围为n,m∈(-∞,10]
则(nmax , mmax )=(10,10),因此,二维数组不能只声明10*10大小的,10 10大小的二维数组对应的(nmax , mmax )=(9,9)。因此应至少声明大小11 * 11,推荐声明大小1515,int a[15][15]
应题目要求对其进行初始化int a[15][15]={ };
实操代码
#include<iostream>
using namespace std;
int main(){
int a[15][15]={},n,m;
cin >> n >> m;
cout << a[n][m] <<endl
return 0;
}
2.展示场地
题目分析
题意为,需要开出一个最小10 * 10 大小的方阵,在方阵内,老师会随即指出一个长宽大小分别为m,n的矩形,检查对应矩形内是否被初始化。题目中提到,极限值为10,则下标最大为10,按照惯例开出15,则int array[15][15]
实操代码
#include<iostream>
using namespace std;
int main(){
int array[15][15]={},n,m,i,j;
cin >> m >> n;
for(i=1;i<=n;i++){
for(j=1;j<=m;j++){
cout << array[i][j] <<" ";
}
cout << endl;
}
return 0;
}
3.“最高的同学”
题目分析
据题意可知,输入分为:二维数组属性的输入,即长n宽m;以及二维数组元素(身高h)的输入。
输出分为:将输入的二维数组元素按照输入的二维数组属性进行原样输出,同时输出元素的最大值
输入的有效数据范围:n,m∈[1,10];h∈[100,200]
题目中只提到了n+1个数据,以及数据的实例为身高,但并未直接说明数据类型,考虑实际情况,身高可能为小数例如177.5,因此保险起见,数据类型写为double双精度浮点小数型
实例代码
#include<iostream>
using namespace std;
int main(){
double array[15][15],maxnum=-1e9;
int n,m,i,j;
cin >> n >> m;//输入行列
for(i=1;i<=n;i++){
for(j=1;j<=m;j++){
cin>>array[i][j];//输入二维数组的值
if(array[i][j]>maxnum){
maxnum=array[i][j];
//将当前输入数据与最大值相比较
//如果当前数据大于当前最大值,则将最大值赋值为当前值
}
}
}
//输出
for(i=1;i<=n;i++){
for(j=1;j<=m;j++){
cout<< array[i][j] << " ";//输出二维数组
}
cout << endl;
}
cout << maxnum; //输出最高值
return 0;
}
4.最后的请求(已解决)
题目分析
题目为上道题的变式,两题目输入的内容相同,输出略有不同
上道题中输出要求为:
- 将输入的二维数组元素按照输入的二维数组属性进行原样输出
- 同时输出元素的最大值
本题目中输出的第一条与上题相同;第二条,要求输出元素最小值所在二维数组中的位置,而不是元素的最大值
题目中已经说明身高为整数,则二维数组的数据类型声明为整型即可int array[15][15]
;
由于cin >>
和cout <<
语句为自适应输入输出语句,因此也可将二维数组定义为double双精度浮点小数型,即double array[15][15]
,输入输出时会进行数据类型的自适应
但是,假使我们是使用scanf('')
和printf
进行输入输出操作,就不可以将本题中的二维数组定义为double双精度浮点小数型,因为其在输入输出时无法进行自适应
根据输入样例中,最小值为134,在样例输出中对应的输出坐标为2 1即第二行第一列,因此判断,在该题目中,下标应从1开始,而不是0
实例代码
#include<iostream>
using namespace std;
int main()
{
int array[15][15]={},minx=2e9;
int m, n, i,j,x,y;//x,y用于存储minx坐标
cin >> n >>m;
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
cin >> array[i][j];//输入数组元素
if(array[i][j]<minx)
{
minx=array[i][j];
x=i;
y=j;
}
}
}
//输出
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
cout<<array[i][j];
cout << " ";
}
cout << endl;
}
cout << x <<" "<<y;
return 0;
}
常见问题:访问越界与死循环
如上述代码,若第29行为for(j=1;i<=m;j++)
则会出现在内层循环的结束条件为外层的循环变量的情况
因此会出现访问越界,并形成死循环
5.数据魔方
题目分析
输入依次为输入二维数组n行,m列,以及二维数组内的元素
根据示例可知,要求对输入的数据进行列倒叙排序进行输出,因此,在输出到列的循环中,循环应为j初始为m,持续j--
,直至j>=1
而不是此前的j++到j<=n
故循环操作应为for(j=m;j--;j<=1)
题目中并未说明输入的二维数组的数据类型,对于输入的数据吧,保险起见我们是用double双精度浮点小数型,并使用cin
和cout
语句进行自适应输入输出
实例代码
#include<iostream>
using namespace std;
int main() {
double array[15][15];
int n, m, i, j;
cin >> n >> m;
for (i = 1; i <= n; i++) {
for (j = 1; j <= m; j++) {
cin >> array[i][j];
}
}
for (i = 1; i <= n; i++) {
for (j = m; j >= 1; j--) {
cout << array[i][j] << " ";
}
cout << endl;
}
return 0;
}
二维数组元素蛇形排序
#include<iostream>
using namespace std;
int main() {
int array[15][15] = {}, n, m, i, j, cnt;
cin >> n >> m >> cnt;
for (i = 1; i <= n; i++)//行循环
{
if (i % 2 == 0)//如果是偶数行
{
for (j = m; j >= 1; j--) {
array[i][j] = cnt;
cnt++;
}
} else {
for (j = 1; j <= m; j++) {
array[i][j] = cnt;
cnt++;
}
}
}
for (i = 1; i <= n; i++) {
for (j = 1; j <= m; j++) {
cout << array[i][j] << " ";
}
cout << endl;
}
return 0;
}
二维数组的遍历
任意二维数组的遍历
#include<iostream>
#include<cstdlib>//数学头文件,
using namespace std;
int a[100][100];//创建一个10*10的二维数组
int main(){
int n=10,m=30;//规定数组的有效范围为10*30
//cin>>n>>m;
for(int i=0;i<n;++i){//循环条件:创建变量i=0,当i<n时,进入循环
for(int j=0;j<m;++j){//循环条件 : 创建变量j=0,当j<m时进入循环
//cin>>a[i][j];
a[i][j]=rand()%5;//将二维数组中的i和j设为随机值,随机值取模于5 ,即随机数的值 不超过5
}
}
for(int i=0;i<n;++i){
for(int j=0;j<m;++j){
cout<<a[i][j]<<"\t";
}cout<<endl;
}
return 0;
}
二维数组的单行遍历
#include<iostream>
using namespace std;
int main(){
int a[2][2]={};//声明一个2*2的二维数组
a[0][0] = 1;
a[0][1] = 2;
for(int i=0;i<2; i++)
{
cout << a[0][i];
}
return 0;
}
二维数组初始化的探究——遍历法
#include<iostream>
using namespace std;
int main(){
int arry[6][6]={{12,35}
{33},
{97},
{21},
{38},
{75},
};
for(int i=0;i<=5;i++){
for(int j=0;j<=5;j++){
cout<<arry[i][j]<<" ";
}
cout << endl;
}
return 0;
}
}
对于一个二维数组,在赋值时,即使任意一行没有附满,即开了3个单位,只赋值了一个单位,则视为对整行数组进行初始化操作,并对被赋值单位进行赋值,即:二维数组中,在花括号内的行,即使没有被赋值的单位也会被初始化,以此推出int array[2][2]={}
,花括号=初始化
从右上到左下遍历
例题
题目分析
如图,本题目实际上是一个从右上到左下的单项多条对角线的输出规律
横向共m
行,与横向相连接的对角线共计m
条。纵向n
列,仅与纵向相连,未与横向相连的对角线共计n-1
条;因此,共计有 m+n-1
条对角线
对于前m
条对角线来说,对角线一定是从第一行开始,即起始点对应的行的序数一定为1;并且是从第一列分布到第1m
列结束,即起始点对应的列的序数时1~m
所以剩下的n-1
条对角线来说,即起始点对应的行的序数从1开始递增(++)到n
-1结束;对应的列数始终为第m
行
因此,我们仍采用对角线区分,分为两部分,前m
条对角线一部分,后n-1
条对角线一部分
并且,由于关于对角线的循环次数不固定,因此我们需要使用while
循环,
同时满足行最后指向的位置不能超过第一行、列最小=1,因此应该为while(h<=m && l>=1)
数字矩阵
反之字矩阵
反之字矩阵,即从下至上从右至左方向的蛇形二维矩阵
问题分析
根据本题,可以总结出主要的考察是对于反之字矩阵的输出
即从下至上从右至左方向的蛇形二维矩阵
此时,输出的两种顺序从右至左、从左至右同时出现,且与矩阵的奇数/偶数行无直接关系
因此,我们可以定义一个布尔类型的变量flag
用于切换两种输出顺序
(因为布尔类型具有非真既假,非1即0的双面性,符合我们对于两种状态的切换需求,故选用布尔类型)
我们默认为最下面,即循环开始的一行所对应的状态为true
,则次行的状态为false
,即进行取反操作flag = !flag
实例代码
#include<iostream>
using namespace std;
int main()
{
int array[105][105],n,m,i,j;
int cnt=1;//填充矩阵的数字,初始值为1
bool flag=true;
cin >> n >> m;
for(i=n; i>=1; i--) //共计n行,故从1开始,若从0开始,则到n-1时是n行 顺序从下到上,i--
{
if(flag==true)//输出顺序:右—左
{
for(j=m; j>=1; j--)
{
array[i][j]=cnt++;//输出赋值
}
}
else//输出顺序:左—右
{
for(j=1; j<=m; j++)
{
array[i][j]=cnt++;
}
flag =!flag;
}
}
for(i=1; i<=n; i++)
{
for(j=1; j<=m; j++)
{
cout << array[i][j] <<" ";
}
cout << endl;
}
return 0;
}
蛇行矩阵
问题分析
输入n
,n同时表示输出矩阵的行和列,因此,输出的矩阵一定为一个正方形矩阵,1且,矩阵的输出顺序的对角线排列共有2n-1
条对角线
根据实例内容,该题目实际是进行了一个斜对角线的输出排序,输出顺序如图
由图我们可知,第奇数条对角线的方向永远是左下至右上 ,第奇数条对角线的方向永远是右上至左下
- 当对角线的方向为左下至右上时(即第奇数条对角线),行序递减,列序递增
i--;j++
- 当对角线的方向为右上至左下时(即第偶数条对角线),行序递增,列序递减
i++;j--
因此,我们需要考虑到三个平面位置因素,行i
、列j
、对角线k
,因此我们需要三层for循环来遍历这个二维数组
并且,由于对角线的变化是最慢的,因此,对角线k
应处于最外层循环,行i
应处于中层循环,列j
应处于最内层循环
==Tip:
对于多层嵌套循环体来说,最内层循环变化最快,越靠外层的循环体变化速度越慢,最外层循环变化最慢==
同时,我们可以发现,对于矩阵内的一个位置的行、列、所在对角线满足i + j = k - 1
的关系
实例代码
//一个数取模于2等于0,即被2整除,则说明该数字为偶数
#include<iostream>
using namespace std;
int main()
{
int array[105][105],n,i,j,k,cnt=1;
cin >> n;
for(k=1;k<=2*n-1;k++) //对角线
{
if(k%2==0)//向下(左下)走 偶数行
{
for(i=0; i<n; i++)
{
for(j=n-1; j>=0; j--)
{
if(i+j==k-1)
{
array[i][j]=cnt++;
}
}
}想·
}
else //奇数行 向右上走
{
for(i=n-1; i>=0; i--)
{
for(j=0; j<n; j++)
{
if(i+j==k-1)
{
array[i][j]=cnt++;
}
}
}
}
}
for(i=0;i<=n;i++)
{
for(j=0;j<=n;j++)
{
cout<< array[i][j]<<" ";
}
cout << endl;
}
return 0;
}
环形矩阵
题目分析
根据题目,输入的一个变量n代表了输出矩阵的一个圈数,每圈圈内数字相同,且数字随圈层由外到内递增
也就是说,当输入n
圈时,矩阵的长和宽均为2n-1
,因此最外层填充时i
应该到2n-1
结束,随层数k
增加而变化为2n-k
因此,我们需要考虑到三个平面位置因素,行i
、列j
、圈层k
,因此我们需要三层for循环来遍历这个二维数组
并且由于圈层的变化是最慢的,因此圈层k
应处于最外层循环
由于输出矩阵填充的数字和就是其圈层,因此无需设置填充的数字的变量cnt
,直接填充圈层序数k
==本题涉及到了多层嵌套循环,因此应注意避免死循环以及访问越界的问题==
实例代码
#include<iostream>
using namespace std;
int main()
{
int array[205][205],n,i,j,k;
cin >> n;
for(k=1; k<=n; k++) //圈层
{
for(i=k; i<=2*n-k; i++)
{
for(j=k; j<=2*n-k; j++)
{
array[i][j]=k;
}
}
}
for(i=1; i<=2*n-1; i++)
{
for(j=1; j<=2*n-1; j++)
{
cout << array[i][j] << " ";
}
cout << endl;
}
return 0;
}
总结
本篇作者:Eason 审校:汐湫