手把手教你写人工智能之地形导航系统

项目需求

2018 年 11 月 26 日,“洞察”号火星探测器在火星上成功着陆,执行人类首次探究火星“内 心深处”的任务。火星上地形比较复杂,高低起伏,有山峰和低谷,稍有不慎,就会引起“翻 车”。因此我们必须要识别地形上的各个最高点(峰点)和最低点(谷点),以便为探测器 提供导航数据。

042badabcc9b496a910487a31f897e79.png

峰点就是一个其周围所有点的海拔都低于它的点

 

203

109

181

289

300

264

190

250

188

现在我们要做的就是分析来自地图上的海拔数据,以确定地形中峰点的数目和位置

 

二维数组

数组,就是多个同类型的元素的有序“组合”。如下的一组女兵,注:同类型是指都是女兵,不能混入男兵 -:)

90853cd767d34bd29b5367b8a1cbca51.png

 

二维数组,就是指含有多个数组的数组!

0b5aa524d52c4710886ceeb2c6781460.png

如果把一维数组理解为一行数据,那么,二维数组可形象地表示为行列结构。

二维数组的定义

和数组一样,需要先定义,再使用。

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};

a[0][0]

1

a[0][1]

2

a[0][2]

3

a[0][3]

4

a[1][0]

5

a[1][1]

6

a[1][2]

7

a[1][3]

8

a[2][0]

9

a[2][1]

10

a[2][2]

11

a[2][3]

12

如下图表示,左侧表示的是一个大小为M+1的一维数组,右侧表示的是一个大小为(M+1)*(N+1)的二维数组。

8d01823dd8094831becccc16239fc2c2.png

 

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");

}

11

二维数组的存储方式

设置断点调试,可以看到二位数组中的所有元素在内存中的存储方式

aaedec8366bd4899a0058da03c9d72f9.png

 307acf9ff9924b3f94d83e7da78af553.png

 

 多维数组

上面讨论的二维数组的相关内容都适用于三维数组或更多维的数组。声明一个三维数组: int girl[3][8][5];

可以把一维数组想象成一排女兵,把二维数组想象成一个女兵方阵,把三维数组想象成多个女兵方阵。这样,当你要找其中的一个女兵时,你只要知道她在哪个方阵(从 0、1、2 中选择),在哪一行(从 0-7)中选择,在哪一列(从 0-4 中选择)

03edcc0528634a47b4914eb771b2c816.png

 

二维数组作为函数的参数

切记!数组作为函数的参数传递,不是单纯的值传递,传递的是数组本身。

二维数组作为函数的参数:

#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 的网格, 加了下划线的网格即为峰点。

5039    5127   5238    5259   5248    5310   5299

5150    5392   5410    5401   5320    5820   5321

5290    5560   5490    5421   5530    5831   5210

5110    5429    5430    5411   5459    5630   5319

4920    5129   4921    5821   4722    4921   5129

5023    5129   4822    4872   4794    4862   4245

为了描述峰点的位置,我们需要使用一个位置方案:使用二维数组描述

假定左上角是[0][0],那么向下移动,则行号加 1;向右移动,则列号加 1, 那么这些峰点的位置就可以描述为:[2][1]   [2][5]    [4][3]。

位置确定后,与周围 4 个邻节点比较即可确定峰点!(注:网格边界点缺乏 4 个相邻点不计算峰点)地形数据保存于文件中。

 

49997b3f13ba49edb4ac1b2ea55c3709.png

 

算法设计

  1. 将地形数据从文件读入二维数组;
  2. 逐行遍历二维数组的每个元素,确定是否峰值并打印结果。
#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;
}

 

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会飞的鱼-blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值