STL 库基础概念与示例
一、STL 库基础概念与示例
1. 容器分类
顺序容器
- 核心特性:按元素插入顺序存储,支持下标访问(类似数组),动态扩展内存。
- 典型容器:
vector
(动态数组)。 - 适用场景:需要频繁按顺序访问、尾部插入 / 删除的场景(如队列、栈模拟)。
关联容器
- 核心特性:按元素值的大小自动排序(默认升序),存储位置由值决定,键唯一(
set
/map
的键不可重复)。 - 典型容器:
set
:键值合一(存储的值即键),用于唯一值存储和快速查找。map
:键值对存储(key-value
),键唯一,值可重复。
- 底层结构:二叉搜索树(
set
/map
默认使用红黑树,插入时自动平衡排序)。
2. 常用容器操作对比
操作 | vector(顺序容器) | set(关联容器) | map(关联容器) |
---|---|---|---|
构造 | vector<int> v; | set<int> s; | map<string, int> m; |
新增元素 | v.push_back(10); (尾部插入) | s.insert(10); (自动去重、排序) | m.insert({"apple", 5}); 或 m["apple"] = 5; |
删除元素 | v.erase(it); (需迭代器定位) | s.erase(10); (直接传值删除) | m.erase("apple"); (按键删除) |
修改元素 | v[0] = 20; (下标直接修改) | 不可直接修改键(需 s.erase(old_val); s.insert(new_val); ) | m["apple"] = 10; (直接修改值) |
查询元素 | 需自定义 find 函数(线性查找) | s.find(10) != s.end(); (返回迭代器) | m.find("apple") != m.end(); (按键查找) |
遍历方式 | 下标遍历、迭代器、范围 for | 迭代器、范围 for (不支持下标) | 迭代器、范围 for |
排序 | 需调用 sort(v.begin(), v.end()); | 自动排序(插入时二叉树调整) | 自动按键排序 |
3. 关键注意点
vector
不支持<<
运算符输出- 需手动遍历元素,不能直接
cout << v;
。
- 需手动遍历元素,不能直接
set
的键不可修改- 若需修改键值,必须先删除旧元素,再插入新元素。
map
的键唯一,值可重复- 键用于排序和查找,值可灵活修改(如统计频率)。
二、示例代码
示例 1:vector 存储整数(顺序容器)
cpp
#include <iostream>
#include <vector>
#include <algorithm> // 用于sort
using namespace std;int main() {vector<int> nums;// 插入元素nums.push_back(3);nums.push_back(1);nums.push_back(2);// 遍历(下标方式)cout << "插入顺序:";for (int i = 0; i < nums.size(); i++) {cout << nums[i] << " "; // 输出:3 1 2}// 排序(需手动调用sort)sort(nums.begin(), nums.end());cout << "\n排序后:";for (auto num : nums) { // 范围for遍历cout << num << " "; // 输出:1 2 3}return 0;
}
关键点:vector
按插入顺序存储,需手动排序,支持下标和迭代器遍历。
示例 2:set 统计唯一字符(关联容器)和 去重
cpp
#include <iostream>
#include <set>
using namespace std;int main() {string str = "hello";set<char> unique_chars;// 插入字符(自动去重,'l' 只存一次)for (char c : str) {unique_chars.insert(c);}// 遍历(自动排序:'e', 'h', 'l', 'o')cout << "唯一字符:";for (char c : unique_chars) {cout << c << " "; // 输出:e h l o}return 0;
}
#include <iostream> // 包含输入输出流头文件,用于cin/cout
#include <set> // 包含set容器头文件,用于有序存储和自动去重
#include <string> // 包含字符串头文件,用于处理输入的字符序列
using namespace std; // 使用标准命名空间,简化代码书写// 定义Data类,用于存储字符及其出现次数
class Data {
private:char ch; // 私有成员:存储字符(作为set的键,决定排序和唯一性)int count; // 私有成员:存储字符出现的次数
public:// 构造函数:初始化字符和计数,默认计数为1(首次出现)Data(char ch, int count = 1) : ch(ch), count(count) {}// 重载<运算符:用于set容器排序(按字符的ASCII值升序)bool operator<(const Data& r) const { return ch < r.ch; // 比较字符大小,确保set有序存储}// 重载后增量运算符++(int):处理字符重复出现的计数增加void operator++(int) const { // 由于函数为const,需通过强制类型转换修改非const成员(注意:此写法不推荐,可能破坏const正确性)((Data*)this)->count++; }// 显示函数:输出字符及其出现次数void show() const { cout << ch << "出现了:" << count << "次" << endl; }
};int main() {while (1) { // 无限循环,持续处理用户输入set<Data> s; // 创建set容器,存储Data对象(自动去重、按ch排序)string str; // 用于存储用户输入的字符串cout << "请输入字符:";cin >> str; // 读取用户输入的一行字符// 遍历输入字符串的每个字符for (int i = 0; str[i]; i++) { // 插入字符到set中,insert返回pair<iterator, bool>:// first为插入位置迭代器,second表示是否插入成功(true=新插入,false=已存在)auto p = s.insert(Data(str[i])); // 如果插入失败(字符已存在),则找到已存在的元素并增加计数if (!p.second) { (*p.first)++; // 通过迭代器访问已存在的Data对象,调用后增量运算符}}// 遍历set,输出每个字符的出现次数(set自动按ch排序)for (auto ele : s) { ele.show(); // 调用show方法输出结果}}return 0;
}
关键点:set
自动去重并按字符 ASCII 值排序,插入重复元素无效。
示例 3:map 统计单词频率(关联容器)
cpp
#include <iostream>
#include <map>
#include <string>
using namespace std;int main() {string sentence = "apple banana apple orange";map<string, int> word_freq; // key=单词,value=频率// 统计频率(用operator[]修改值)for (string word : {"apple", "banana", "apple", "orange"}) {word_freq[word]++; // 键不存在时自动创建,值初始化为0后+1}// 遍历输出(按键自动排序:apple, banana, orange)cout << "单词频率:" << endl;for (const auto& pair : word_freq) {cout << pair.first << ": " << pair.second << endl;// 输出:// apple: 2// banana: 1// orange: 1}return 0;
}
关键点:map
按键自动排序,operator[]
简化值的修改,键唯一(重复插入同一键会更新值)。
三、总结
- 顺序容器(如
vector
)适合 “按顺序操作” 场景,需手动处理排序和查找。 - 关联容器(如
set
/map
)适合 “快速查找、去重、排序” 场景,底层二叉树结构保证高效操作(O(log n)
)。 - 开发中根据需求选择容器:需顺序访问选
vector
,需唯一键选set
,需键值对选map
。