CC++ & Algorithm

vector动态数组

中等5
语言版本:C++
概述:学会使用vector,就像拥有一个可以随时变长变短的铅笔盒,轻松管理一堆数据。

vector动态数组——像魔法铅笔盒一样方便的容器

你有没有遇到过这种情况:写作业时要记下全班同学的成绩,但一开始不知道有多少个同学?如果使用普通数组,必须提前定好大小,比如“最多50人”,但万一有51个人,数组就装不下了;或者只有10个人,却浪费了40个空位。C++里的 vector动态数组 就像一个神奇的铅笔盒,它可以根据你放进去的铅笔数量自动变长或变短——放多少支铅笔,盒子就多大,不多不少刚刚好!


一、什么是vector?

vector 是C++标准模板库(STL)中的一种容器,它本质上是一个可以自动调整大小的数组。你可以随意往里面添加或删除元素,它自己会管理内存空间,完全不用你操心“容量不够”的问题。和普通数组一样,它也可以通过下标快速访问元素(O(1)时间),但比数组灵活得多。

生活中的类比

  • 普通数组像固定大小的文具盒(只能装10支笔,多了放不下,少了空荡荡)
  • vector像伸缩铅笔袋(可以塞进20支笔,也可以只放3支笔,袋子会贴合大小)

二、怎么创建一个vector?

1. 包含头文件

使用vector之前,必须在程序开头写:

#include <vector>   // vector的头文件

2. 定义vector的几种常见方式

#include <vector>
using namespace std;

vector<int> scores;              // 创建一个能装整数的空vector,名字叫scores
vector<double> heights;           // 装小数的vector,名字叫heights
vector<string> names;             // 装字符串的vector,名字叫names(需要#include <string>)

// 也可以提前指定大小(但后续还能继续增加)
vector<int> grades(30);           // 创建一个vector,初始有30个元素,默认值都是0
vector<int> ages(10, 7);          // 创建一个vector,初始有10个元素,每个元素都是7(比如10个小朋友都7岁)

// 还可以用花括号直接列出初始值(C++11开始支持)
vector<int> lucky_numbers = {1, 3, 7, 9, 15};  // 创建一个包含5个幸运数字的vector

创建空的vector就像拿了一个空的铅笔盒,准备往里装“铅笔”。


三、往里面装东西——push_back()

push_back() 方法在vector的末尾添加一个新元素。这是最常用的添加方式。

vector<int> scores;               // 空vector
scores.push_back(90);             // 装进第一个成绩90
scores.push_back(85);             // 装进第二个成绩85
scores.push_back(100);            // 装进第三个成绩100
// 现在scores里有3个元素:90, 85, 100

这个过程就像你往铅笔盒里一支一支地放铅笔,放进去的顺序就是它们在vector中的顺序。

除了push_back,还有pop_back():删除最后一个元素

scores.pop_back();                // 删除最后一个元素(100),现在scores只剩90和85

四、查看里面的东西——下标访问和at()方法

cout << scores[0] << endl;        // 输出第一个元素:90
cout << scores.at(1) << endl;     // 输出第二个元素:85

注意:下标从0开始,就像排队时第一个人的编号是0,第二个人的编号是1。

区别

  • scores[i]:如果 i 超出了范围(比如访问 scores[5] 而vector只有3个元素),程序不会报错,而是返回一个垃圾值,非常危险。
  • scores.at(i):如果 i 越界,程序会抛出一个异常并终止(在CSP-J中通常表现为程序崩溃)。所以推荐在不确定下标是否合法时用 .at()

五、知道有多少个元素——size()和empty()

cout << "一共有" << scores.size() << "个成绩" << endl;   // 输出 2

if (scores.empty()) {
    cout << "当前vector是空的" << endl;
} else {
    cout << "当前vector不为空,有" << scores.size() << "个元素" << endl;
}

size() 返回当前元素个数(类型是 size_t,可以当作整数用)。 empty() 返回 true 如果vector是空的,否则返回 false


六、遍历vector——找出所有元素

最传统的方式是用for循环配合下标:

for (int i = 0; i < scores.size(); i++) {
    cout << scores[i] << " ";
}

从C++11开始,还可以用 范围for循环(也叫foreach),写起来更简洁:

for (int score : scores) {      // 每次循环,score就依次等于scores里的每一个元素
    cout << score << " ";
}

两种方法效果一样,但范围for循环不需要操心下标,也不怕写错边界。


七、新手容易犯的错误

错误1:忘记包含头文件

// 忘了 #include <vector>
vector<int> v;   // 编译错误:vector未定义

正确做法:在文件开头加上 #include <vector>,并且加上 using namespace std; 或使用 std::vector

错误2:用下标访问空vector

vector<int> v;   // 空的
v[0] = 10;       // 严重错误!v[0]不存在,程序可能崩溃或修改了不该碰的内存

正确做法:先添加元素,或者用 push_back 添加第一个元素,或者用 v.resize(1) 分配空间后再访问。

错误3:混淆 size() 和普通整数

size() 返回的是无符号整数 size_t,如果与一个有符号整数(比如 int)比较,编译器可能会给出警告。比较安全的写法是:

for (int i = 0; i < (int)scores.size(); i++)   // 强制转换int

或者直接用 size_t i 循环。

错误4:不要用 [] 添加新元素

vector<int> v;
v[0] = 5;       // 错误!v现在是空的,不能这样赋值

一定要用 push_back 或者先 resize 后再用 []


八、完整示例:统计成绩并计算平均分

这个程序先让用户输入多个成绩(输入-1结束),然后显示所有成绩和平均分。

#include <iostream>
#include <vector>      // vector头文件
using namespace std;

int main() {
    vector<int> scores;            // 空的vector,存放成绩
    int score;                     // 临时变量,接收输入

    cout << "请输入成绩(输入-1结束):" << endl;
    while (true) {
        cin >> score;
        if (score == -1) {
            break;                 // 结束输入
        }
        scores.push_back(score);   // 把成绩放入vector
    }

    // 如果没有任何成绩,直接退出
    if (scores.empty()) {
        cout << "没有输入任何成绩。" << endl;
        return 0;
    }

    // 输出所有成绩
    cout << "你一共输入了 " << scores.size() << " 个成绩:";
    for (int s : scores) {         // 范围for循环,s依次取每个成绩
        cout << s << " ";
    }
    cout << endl;

    // 计算总和
    int sum = 0;
    for (int s : scores) {
        sum += s;
    }
    double average = (double)sum / scores.size();   // 注意:把其中一个转为double
    cout << "平均分:" << average << endl;

    return 0;
}

运行示例

请输入成绩(输入-1结束):
95
88
76
100
-1
你一共输入了 4 个成绩:95 88 76 100 
平均分:89.75

九、常用其他操作一览(供查阅)

操作作用示例
v.clear()清空所有元素(变成空vector)scores.clear();
v.pop_back()删除最后一个元素scores.pop_back();
v.insert(pos, value)在位置pos前插入一个元素scores.insert(scores.begin()+1, 90);
v.erase(pos)删除位置pos处的元素scores.erase(scores.begin());
v.resize(n)重新设置大小为n,多出的元素用默认值填充scores.resize(10);
v.front()返回第一个元素int first = scores.front();
v.back()返回最后一个元素int last = scores.back();

注意:inserterase 会引起元素的移动,效率较低(O(n)),大量插入删除不如使用 list


十、小练习(动手试试)

  1. 创建一个 vector<string> 存放你的三个好朋友的名字(用 push_back 添加),然后使用范围for循环输出每个名字。别忘了包含 <string> 头文件哦!

  2. 创建一个 vector<int> 存放1到10的整数(用for循环 push_back),然后删除最后一个数,再输出剩下所有数的和。

  3. 挑战题:从键盘读入5个价格(double类型),存入vector,然后找出最高价和最低价。


十一、相关指引

vector是STL中最常用的序列容器。学完vector后,你还可以学习:

  • algorithm 头文件:配合vector使用排序、查找等算法(比如 sort(v.begin(), v.end()) 可以把成绩从小到大排序)
  • list 双向链表:如果需要在中间频繁插入或删除元素,用list比vector更高效
  • stackqueue:基于vector或deque实现的栈和队列,适合“后进先出”或“先进先出”的场景
  • map 映射表:像字典一样存储键值对,例如把学生姓名映射到他的成绩

掌握了vector,你就掌握了C++中最实用、最灵活的数据容器之一!快去试试用vector解决你作业里的数据存储问题吧。

例题精讲

1单选题

下列关于C++中vector动态数组的描述,哪一项是正确的?

A使用vector时必须预先指定大小,否则无法添加元素
Bvector在内存中不一定是连续存储的
C可以通过push_back()方法在vector末尾添加元素
Dvector的size()返回的是当前容量(capacity)
2判断题

在C++中,使用vector<int> v;声明一个空的vector后,立即执行cout << v[0];不会导致程序运行错误。

3填空题
以下代码使用vector存储整数并输出所有元素,请补全缺失的部分。

#include <iostream>
#include <vector>
using namespace std;
int main() {
    vector<int> v;
    for(int i=0; i<5; i++) {
        ___;   // 将i的平方添加到vector末尾
    }
    for(int i=0; i<v.size(); i++) {
        cout << ___ << " ";  // 输出第i个元素
    }
    return 0;
}
4单选题

关于vector的迭代器,以下说法正确的是?

Avector的迭代器属于随机访问迭代器,支持+和-等算术操作
B在vector中插入元素后,所有迭代器仍然有效
Cvector的begin()和end()迭代器指向同一个位置
D对空vector调用begin()和end()会报错
5判断题

使用reserve()可以改变vector的size,使元素个数增加。