CC++ & Algorithm

C++数组的查找与统计

较难18
语言版本:C++Python
概述:学会在一堆数据中查找某个值是不是存在,并且统计某个值出现了多少次。

在数组中查找和统计:像侦探一样寻找线索

想象一下,你有一堆同学的成绩单,你想知道有没有人考了100分?或者想知道全班有多少人及格了?在编程中,这些操作分别叫做查找(找某个值是否存在)和统计(数数某个条件满足了几次)。数组就像一列整齐的储物柜,里面装着数据,我们只需要按顺序检查每个柜子就行了。

1. 顺序查找:一个一个问,直到找到答案

顺序查找是最简单的方法:从数组的第一个元素开始,挨个和要找的目标比较。如果相等,就说明找到了,可以记录位置并停下来。如果全部比较完都没找到,那就是不存在。

生活例子:在排队找朋友

你和朋友约好在电影院见面,但队伍很长,你不知道他在哪。你只能从队伍第一个人开始,一个个看脸:“是你吗?”如果不是,继续看下一个。直到找到朋友,或者走到队伍尽头。

代码实现:找有没有77分

下面的程序检查一个成绩数组里是否包含77分。如果找到,就输出它的位置(下标),并用一个布尔变量found记录是否找到。

#include <iostream>
using namespace std;

int main() {
    int scores[7] = {88, 72, 77, 95, 77, 60, 45}; // 7个成绩
    int target = 77;          // 要查找的目标分数
    bool found = false;       // 标记:是否找到,初始为false
    
    // 从第一个元素开始,逐个比较
    for(int i = 0; i < 7; i++) {
        if(scores[i] == target) {
            found = true;     // 找到了
            cout << "找到了77分,位置是下标 " << i << endl;
            break;            // 如果只想找第一次出现,就及时退出循环
        }
    }
    
    if(!found) {
        cout << "没有找到 " << target << " 分" << endl;
    }
    return 0;
}

注意break会让循环提前结束。如果数组里有多个77分,上面的程序只会报告第一个出现的位置。如果你想找出所有位置,可以删除break,并在循环结束后看看found是不是true

进阶:记录所有位置

如果想输出所有77分的位置,可以去掉break,并在循环外判断是否找到:

#include <iostream>
using namespace std;

int main() {
    int scores[7] = {88, 72, 77, 95, 77, 60, 45};
    int target = 77;
    bool found = false;       // 标记是否至少找到一个
    
    cout << target << "分出现的位置: ";
    for(int i = 0; i < 7; i++) {
        if(scores[i] == target) {
            found = true;
            cout << i << " "; // 逐个输出下标,不换行
        }
    }
    if(!found) {
        cout << "没有";
    }
    cout << endl;
    return 0;
}

2. 统计计数:数一数满足条件的有几个

统计比查找多一个步骤:不是找到就停,而是每遇到一个满足条件的,就把计数器加1。循环结束后,计数器的值就是结果。

生活例子:数苹果里红色的有几个

你有8个苹果,颜色分别是红、绿、红、黄、红、红、绿、绿。你想知道红色苹果有几个。于是你一个一个看,“这个是红色吗?是,计数器加1……不是,跳过。”最后计数器显示有4个红色苹果。

代码实现:统计及格人数和具体分数出现次数

下面统计成绩数组中大于等于60分的人数(及格人数),以及60分本身出现了几次。

#include <iostream>
using namespace std;

int main() {
    int scores[8] = {72, 58, 90, 45, 88, 60, 95, 50};
    int passCount = 0;      // 及格人数计数器,初始为0
    
    for(int i = 0; i < 8; i++) {
        if(scores[i] >= 60) {
            passCount++;    // 每遇到一个及格的就加1
        }
    }
    cout << "及格人数: " << passCount << endl;
    
    // 也可以统计某个特定值出现了几次,比如60分
    int count60 = 0;
    for(int i = 0; i < 8; i++) {
        if(scores[i] == 60) {
            count60++;
        }
    }
    cout << "60分出现的次数: " << count60 << endl;
    
    return 0;
}

注意:统计时不需要break,因为我们要检查所有元素。计数器每次加1,最后的值就是总数。

3. 条件统计:按范围或特征统计

除了统计等于某个值,还可以统计满足某个范围(比如90分以上、不及格人数)或某个特征(比如是偶数)的元素个数。方法完全一样,只是if里的条件不同。

例子:统计90分以上的学霸人数

int highScoreCount = 0;     // 90分以上的人数
for(int i = 0; i < 8; i++) {
    if(scores[i] > 90) {
        highScoreCount++;
    }
}
cout << "90分以上的人数: " << highScoreCount << endl;

例子:统计不及格人数(小于60)

int failCount = 0;          // 不及格人数
for(int i = 0; i < 8; i++) {
    if(scores[i] < 60) {
        failCount++;
    }
}
cout << "不及格人数: " << failCount << endl;

4. 新手容易犯的错误

  • 忘记初始化计数器:如果没给passCount设初始值(比如直接int passCount;),它的值可能是随机的,加出来的结果也乱七八糟。一定要初始化为0。
  • 在查找时忘记用break:如果只是想找“有没有”,找到后不退出循环,会继续比较后面的元素,虽然逻辑上没错,但浪费了时间。如果还记录了位置,最后的位置会是最后一个出现的位置,而不是第一个。
  • =代替==if(scores[i] = target)是赋值,不是比较。赋值表达式的值是赋的值,在C++中非零为真,所以永远会进入if块。这是最常见的笔误。
  • 数组下标越界:循环条件写成i <= 数组长度,会访问数组最后一个元素后面的位置,程序可能崩溃。记住数组下标从0开始,最大下标是数组长度-1。

5. 完整示例:查找最高分和统计人数

下面把查找和统计结合起来:找出最高分,并统计有多少人达到了这个最高分。

#include <iostream>
using namespace std;

int main() {
    int scores[10] = {72, 88, 95, 91, 73, 95, 68, 82, 95, 60}; // 10人的成绩
    int maxScore = scores[0];   // 假设第一个是最高分
    int maxCount = 0;           // 最高分出现次数
    
    // 第一步:找出最高分
    for(int i = 1; i < 10; i++) { // 从第二个开始比较
        if(scores[i] > maxScore) {
            maxScore = scores[i]; // 更新最高分
        }
    }
    
    // 第二步:统计最高分出现了几次
    for(int i = 0; i < 10; i++) {
        if(scores[i] == maxScore) {
            maxCount++;
        }
    }
    
    cout << "最高分是: " << maxScore << endl;
    cout << "获得最高分的人数: " << maxCount << endl;
    
    return 0;
}

6. 相关指引

学会了数组的查找和统计,你可以:

  • 结合“数组的排序”(比如冒泡排序)来做更高级的数据分析,比如找出中位数。
  • 用二维数组(类似表格)查找某个同学的姓名对应的分数。
  • 用函数封装查找和统计的代码,让主程序更简洁。
  • 进一步学习“二分查找”,它比顺序查找更快,但要求数组事先排好序。

查找和统计就像在图书馆里找书(查找)或者数一数红色封面的书有几本(统计)。掌握了这两个基本操作,你就能用数组解决很多生活里的数据问题啦!

例题精讲

1单选题

假设有一个整型数组 `int arr[5] = {3, 1, 4, 1, 5};`,要统计数字 1 出现的次数,以下哪个代码片段是正确的?

Aint count = 0; for(int i=0;i<5;i++) if(arr[i]==1) count++;
Bint count = 0; for(int i=0;i<5;i++) if(arr[i]==1) count=1;
Cint count = 0; for(int i=1;i<=5;i++) if(arr[i]==1) count++;
Dint count = 1; for(int i=0;i<5;i++) if(arr[i]==1) count++;
2判断题

在长度为 n 的无序数组中查找某个值,如果该值不存在,需要比较全部 n 个元素才能确定。

3填空题
以下代码实现了在数组 `a` 中查找最大值并返回其下标的功能。请补全缺失的代码。

int findMaxIndex(int a[], int n) {
    int maxIdx = 0;
    for (int i = 1; i < n; i++) {
        if (___)
            maxIdx = i;
    }
    return maxIdx;
}
4填空题
统计整数数组 `arr` 中所有大于 0 的元素的个数,并将结果返回。补全代码。

int countPositive(int arr[], int size) {
    int cnt = 0;
    for (int i = 0; i < size; i++) {
        if (___)
            cnt++;
    }
    return cnt;
}
5单选题

对于长度为 10 的整型数组,下列哪种说法是关于顺序查找(线性查找)的正确描述?

A最好情况是第一个元素就是目标值,只需比较 1 次
B最坏情况是目标值在最后一个位置,需要比较 9 次
C平均情况下需要比较 10 次
D如果数组是有序的,顺序查找一定比无序时更快