项目需求
2018 年 11 月 26 日,“洞察”号火星探测器在火星上成功着陆,执行人类首次探究火星“内 心深处”的任务。火星上地形比较复杂,高低起伏,有山峰和低谷,稍有不慎,就会引起“翻 车”。因此我们必须要识别地形上的各个最高点(峰点)和最低点(谷点),以便为探测器 提供导航数据。
峰点就是一个其周围所有点的海拔都低于它的点
现在我们要做的就是分析来自地图上的海拔数据,以确定地形中峰点的数目和位置
二维数组
数组,就是多个同类型的元素的有序“组合”。如下的一组女兵,注:同类型是指都是女兵,不能混入男兵 -:)
二维数组,就是指含有多个数组的数组!
如果把一维数组理解为一行数据,那么,二维数组可形象地表示为行列结构。
二维数组的定义
和数组一样,需要先定义,再使用。
int a[25] ; //一行女兵实例:
int a[5][25]; //五行女兵
//定义了一个二维数组,
//数组名是“a”,
//包含 5 行 25 列,共 125 元素,
//每个元素是 int 类型的变量
二维数组的初始化
int a[3][4]; //二维数组元素的值可能是随机的(全局变量会初始化为 0,局部变量值随机)
方式一 初始化时指定每行的值
int a[3][4]={ //等效于 int a[][4]
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
注:最外围括号内部的每个括号相当于初始化一行,括号中可以省略某些元素的初始化
方式二初始化时从头开始,依次序进行
int a[3][4]={ 1,2,3,4,5,6,7,8,9,10,11,12};
int a[3][4]={ 0}; //所有元素都初始化为 0
注:后面的多个元素可以不指定,不指定全部初始化为 0
#include <stdlib.h> #include <stdio.h> int main(void){ //int ages[5][25];//定义一个二维数组 int i=0, j=0; //初始化 //第一种方式 初始化时指定每行的值 int a[3][4]={ {1},//省略掉得列会默认置零 {5,6,7}, {9,10,11,12} }; //第二种方式 初始化时从头开始,依次序进行 int a1[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}; int a2[3][4]={1};//只初始化第一个,其他得默认置零 for(i=0; i<3; i++){ for(j=0; j<4; j++){ printf("%d ", a[i][j]); } printf("\n"); } system("pause"); return 0; }
二维数组的访问
a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
如下图表示,左侧表示的是一个大小为M+1的一维数组,右侧表示的是一个大小为(M+1)*(N+1)的二维数组。
int i=0, j=0; int a[3][4]; //给数组成员赋值 for(int i=0;i<12; i++){ a[i/4][i%4] = i+1; } //或 for(int i=0;i<3; i++){ for(int j=0;j<4; j++){ a[i][j] = 4*i+j+1; } }
//输出 for(int i=0;i<3; i++){ for(int j=0;j<4; j++){ printf("%d ",a[i][j]); } printf("\n"); }
二维数组的存储方式
设置断点调试,可以看到二位数组中的所有元素在内存中的存储方式
多维数组
上面讨论的二维数组的相关内容都适用于三维数组或更多维的数组。声明一个三维数组: int girl[3][8][5];
可以把一维数组想象成一排女兵,把二维数组想象成一个女兵方阵,把三维数组想象成多个女兵方阵。这样,当你要找其中的一个女兵时,你只要知道她在哪个方阵(从 0、1、2 中选择),在哪一行(从 0-7)中选择,在哪一列(从 0-4 中选择)
二维数组作为函数的参数
切记!数组作为函数的参数传递,不是单纯的值传递,传递的是数组本身。
二维数组作为函数的参数:
#include <stdio.h> #include <stdlib.h> //版本1 指明参数 void print1(int a[3][4]){ for(int i=0;i<3; i++){ for(int j=0;j<4; j++){ printf("%d ",a[i][j]); } printf("\n"); } } //版本1 省略一个高维参数 void print2(int a[][4], int lines){ for(int i=0;i<lines; i++){ for(int j=0;j<4; j++){ printf("%d ",a[i][j]); } printf("\n"); } } int main(void){ //int arr[3][4]={{},{3,4}}; int a[3][4]={0}; int i=0; int j=0; //给数组成员赋值 for(int i=0;i<3; i++){ for(int j=0;j<4; j++){ a[i][j] = 4*i+j; } } print1(a); print2(a); }
常见错误总结
数组定义时编译器不能确定数组的大小
int a[3][] ; int a[][4] ;
int a[3][]={{1,2},{3,4},{5,6}}
一条原则:仅定义时(无初始化)不能省略,有初始化可以省略高维
严禁数组越界
在使用数组时,要防止数组下标超出边界。也就是说,必须确保下标是有效的值。
int a[10] ; a[10]=100; //错误,访问越界,a[10] 的成员是 a[0] - a[9]
int a[3][4]; a[3][0]=666; //错误, a[3][4] 包含了 3 行 4 列的数组,行下标也是从 0 开始,有效范围 0 - 2
数组(无论几维)传参并不是整个数组的复制
#include <stdio.h> #include <stdlib.h> //int arr[3][4]; void fun(int a[3][4]){ for(int i=0;i<3;i++){ for(int j=0;j<4;j++){ a[i][j]=0; } } } int main(void){ //int arr[3][4]={{},{3,4}}; int a[3][4]={0}; int i=0; int j=0; //给数组成员赋值 for(int i=0;i<3; i++){ for(int j=0;j<4; j++){ a[i][j] = 4*i+j; } } fun(a); //输出 for(int i=0;i<3; i++){ for(int j=0;j<4; j++){ printf("%d ",a[i][j]); } printf("\n"); }
项目实现
假设下面的数据代表一个 6 x 7 的网格, 加了下划线的网格即为峰点。
为了描述峰点的位置,我们需要使用一个位置方案:使用二维数组描述
假定左上角是[0][0],那么向下移动,则行号加 1;向右移动,则列号加 1, 那么这些峰点的位置就可以描述为:[2][1] [2][5] [4][3]。
位置确定后,与周围 4 个邻节点比较即可确定峰点!(注:网格边界点缺乏 4 个相邻点不计算峰点)地形数据保存于文件中。
算法设计
- 将地形数据从文件读入二维数组;
- 逐行遍历二维数组的每个元素,确定是否峰值并打印结果。
#include <iostream> #include <string> #include <fstream> #include <Windows.h> using namespace std; #define N 64 bool isPeak(int map[N][N], int nrows, int ncols) { if ((map[nrows][ncols] > map[nrows + 1][ncols]) && (map[nrows][ncols] > map[nrows - 1][ncols]) && (map[nrows][ncols] > map[nrows][ncols + 1]) && (map[nrows][ncols] > map[nrows][ncols] - 1)) { return true; } else { return false; } } int main(void) { string filename; fstream file; int map[N][N]; int ncols, nrows; cout << "请输入你要打开的文件:"; cin >> filename; file.open(filename.c_str()); if (file.fail()) { cerr << "打开文件失败" << endl; exit(1); } file >> nrows >> ncols; if (nrows > N || ncols > N) { cerr << "行或列超出指定范围" << endl; exit(1); } for (int i = 0; i < nrows; i++) { for (int j = 0; j < ncols; j++) { file >> map[i][j]; } } for (int i = 1; i < nrows-1; i++) { for (int j = 1; j < ncols-1; j++) { if (isPeak(map, i, j)) { cout << "行:" << i << "列" << j << "峰值" << map[i][j] << endl; } } } file.close(); system("pause"); return 0; }