CC++ & Algorithm

别再用30个变量存身高了,数组才是批量数据的正确打开方式

想象一下这个场景:你是一位体育老师,刚给全班30个学生测完身高,现在要算出平均身高。如果你的第一反应是拿起计算器一个个加,那这篇文章可能帮不了你。但如果你是那个负责写代码统计的程序员,恭喜你,你即将经历一场"变量地狱"。

让我们先看一个反面教材。假设某个新手程序员真的用30个变量来存身高:

int h1 = 150, h2 = 165, h3 = 172, h4 = 158, h5 = 180;
// 然后继续写25行...
int sum = h1 + h2 + h3 + h4 + h5 + ... // 写到怀疑人生

这代码不仅长得像恐怖片,而且一旦人数从30变成300,代码量直接爆炸。更要命的是,你没法用循环去处理这些变量——因为循环需要的是"规律",而 h1h2h3 这种变量名在编译器眼里就是三个互不相干的陌生人。

数组就是来解决这个问题的。它像一排带编号的抽屉,编号从0开始,每个抽屉里放一个数据。数组的本质,就是把"名字"变成"编号",让数据可以被循环遍历。

三个最常用的数组套路

套路一:累加求和

这是数组最基础的用法,也是后面所有复杂操作的地基。核心就一句话:初始化一个累加器,然后循环把每个元素加进去。

int scores[5] = {88, 92, 73, 85, 96};
int sum = 0;
for(int i = 0; i < 5; i++) {
    sum += scores[i];  // 等价于 sum = sum + scores[i];
}
double average = (double)sum / 5;  // 注意类型转换

这里有个新手最容易踩的坑:平均值计算时忘记转类型sum / 5 是整数除法,结果会截断小数。比如 434 / 5 在C++里等于 86,而不是 86.8。正确做法是 (double)sum / 5 或者 sum / 5.0

套路二:找最大值和最小值

这个套路的关键在于初始值的设定。很多新手喜欢把最大值初始化为0,这在处理身高、成绩这类正数数据时没问题,但如果数据全是负数(比如温度),0就会变成"最大"的那个,结果全错。

正确做法是:用数组的第一个元素作为初始值,然后从第二个元素开始逐个比较。

int maxVal = height[0];  // 不要设成0!
int minVal = height[0];
for(int i = 1; i < n; i++) {
    if(height[i] > maxVal) maxVal = height[i];
    if(height[i] < minVal) minVal = height[i];
}

套路三:倒序输出

这个套路最简单,但最容易在边界条件上出错。数组最后一个元素的下标是 n-1(因为下标从0开始),所以倒序循环要从 n-1 开始,到 0 结束:

for(int i = n-1; i >= 0; i--) {
    cout << height[i] << " ";
}

注意循环条件是 i >= 0,不是 i > 0。很多新手写 i > 0 会漏掉第一个元素。

实战:扫雷游戏的地雷数计算

这三个套路组合起来,就能解决很多实际问题。比如经典的扫雷游戏——计算每个格子周围的地雷数量。

这道题的核心思路是:遍历每个非地雷格子,检查它的8个邻居中有多少个是地雷。这不就是"累加求和"的变体吗?只不过累加的不是数值,而是"邻居是地雷"这个条件的次数。

// 方向数组:8个邻居的偏移量
int dx[] = {-1, -1, -1, 0, 0, 1, 1, 1};
int dy[] = {-1, 0, 1, -1, 1, -1, 0, 1};

// 对每个非地雷格子,统计周围地雷数
if(map[i][j] != '*') {
    int count = 0;
    for(int k = 0; k < 8; k++) {
        int ni = i + dx[k];
        int nj = j + dy[k];
        // 检查边界,防止越界
        if(ni >= 0 && ni < n && nj >= 0 && nj < m && map[ni][nj] == '*') {
            count++;
        }
    }
    map[i][j] = '0' + count;  // 数字转字符
}

这里有个关键点:方向数组。把8个方向的偏移量提前存好,用循环遍历,比手动写8个if判断要简洁得多,也不容易漏掉某个方向。这就是数组的另一个应用——用数据驱动逻辑

常见错误:比你想的更危险

错误一:数组越界

int arr[5];
for(int i = 0; i <= 5; i++) {
    arr[i] = i;  // 当 i=5 时,arr[5] 越界了!
}

arr[5] 访问的是数组之外的内存,程序可能崩溃,也可能不崩溃但产生奇怪的结果。这种bug最难排查,因为它在不同环境下表现不一样。

错误二:未初始化的累加器

int sum;  // 没有初始化!
for(int i = 0; i < 10; i++) {
    sum += a[i];  // sum 的初始值是随机的!
}

sum 没有初始化,它的值是内存中残留的随机数。这就像你往一个没倒空的杯子里加水,最后得到的水量完全不可预测。

错误三:找最大值时初始值设错

前面说过,把最大值初始化为0在处理负数数据时会出错。永远用第一个元素作为初始值,这是最安全的做法。

写在最后

数组的这三种典型用法——累加、找极值、倒序——看起来简单,但它们组合起来能解决大量实际问题。扫雷游戏、成绩统计、数据分析,本质上都是这些基础操作的组合。

进阶建议:学完一维数组后,去了解一下二维数组(处理表格数据)、字符数组(处理字符串)、以及vector容器(动态数组)。这些都是数组的延伸,理解了数组的本质,学起来会事半功倍。

最后送你一句话:编程的核心不是记住语法,而是把复杂问题拆解成简单操作的组合。数组就是你手中的积木,学会用积木搭出各种形状,才是真正的本事。


关于作者

我是赵老师,持有 NOI 信息学奥赛教练证书,拥有 15 年以上的软件开发经验,从事信息学少儿编程教学已有 8 年时间。

这些年累计帮助 多名 学生通过编程特长升入自己心仪的目标学校。

如果你在编程学习上有任何疑问,欢迎联系我:18620372957(微信同号)

这篇文章对你有帮助吗?

成为第一个评价的人

评论0

还没有评论,来抢沙发~

评论加载中...

想系统学习这个知识点?查看完整知识点 →