【C++】STL:掌握STL容器特性与实战用法

举爪爪打招呼

很高兴你点开这篇文章✨

这里会持续更新我喜欢的内容,关注我,一起慢慢变好呀

👍 点赞 ⭐ 收藏 💬 评论


前言

你有没有这种感觉:学完C++的类和模板之后,突然发现自己好像什么都能写了——Stack、Queue、Date、顺序表……但是写完之后又会想:我写的这个有没有bug?扩容策略对不对?拷贝构造有没有深拷贝?

  • 其实这些轮子,C++标准库已经帮我们造好了
  • 这就是STL(Standard Template Library,标准模板库)

STL是C++标准库的核心组成部分,它提供了我们日常开发中最常用的数据结构和算法。不需要我们自己写链表、动态数组、平衡树,直接用就行。

🐶 🐾 ✨ 🐾 🐶


一、STL的六大组件

STL由六个部分组成:

组件作用例子
容器存数据的东西vector、list、map、set
算法对数据进行操作sort、find、reverse
迭代器遍历容器的工具begin()、end()
仿函数行为像函数的对象less、greater
适配器改造容器的接口stack、queue
分配器管理内存allocator

🐶 🐾 ✨ 🐾 🐶


二、最常用的容器:vector

2.1 vector是什么

vector就是一个能自动扩容的动态数组


2.2 基本用法

#include <vector>
#include <iostream>
using namespace std;

int main()
{
    // 创建vector
    vector<int> v1;           // 空的
    vector<int> v2(5, 0);     // 5个0
    vector<int> v3 = {1,2,3,4,5};  // 初始化为1,2,3,4,5
    
    // 尾部插入
    v1.push_back(10);
    v1.push_back(20);
    v1.push_back(30);
    
    // 访问元素
    cout << v1[0] << endl;      // 下标访问,不检查越界
    cout << v1.at(0) << endl;   // 带边界检查
    
    // 获取大小和容量
    cout << v1.size() << endl;      // 实际元素个数:3
    cout << v1.capacity() << endl;  // 当前容量
    
    // 遍历
    for (int i = 0; i < v1.size(); i++)
    {
        cout << v1[i] << " ";
    }
    cout << endl;
    
    // 删除最后一个元素
    v1.pop_back();
    
    // 清空
    v1.clear();
    
    return 0;
}

2.3 我们需要注意的点

  • vector的扩容一般是翻倍扩容
  • size()是实际元素个数,capacity()是已分配空间大小
  • 频繁的push_back可能会导致多次扩容,如果知道要存多少数据,可以先reserve预留空间
vector<int> v;
v.reserve(100);  // 提前预留100个位置,避免多次扩容
for (int i = 0; i < 100; i++)
{
    v.push_back(i);
}

🐶 🐾 ✨ 🐾 🐶


三、迭代器:连接容器和算法的桥梁

3.1 迭代器是什么

可以把迭代器理解成一个能遍历容器的指针。不同容器的内部结构不一样(数组、链表、树),但迭代器提供了一个统一的访问方式。


3.2 基本用法

#include <vector>
#include <iostream>
using namespace std;

int main()
{
    vector<int> v = {1, 2, 3, 4, 5};
    
    // 使用迭代器遍历
    vector<int>::iterator it = v.begin();
    while (it != v.end())
    {
        cout << *it << " ";
        it++;
    }
    cout << endl;
    
    // C++11之后可以用auto简化
    for (auto it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
    
    // 范围for(底层也是用迭代器)
    for (int x : v)
    {
        cout << x << " ";
    }
    cout << endl;
    
    return 0;
}

3.3 迭代器的种类

类型特点适用容器
输入迭代器只读,只能向前istream_iterator
输出迭代器只写,只能向前ostream_iterator
前向迭代器读写,只能向前forward_list
双向迭代器读写,可前可后list、set、map
随机访问迭代器读写,支持it+nvector、deque、array

vector的迭代器是最高级的随机访问迭代器,list的是双向迭代器。

🐶 🐾 ✨ 🐾 🐶


四、常用算法:不用自己写排序了

STL提供了大量算法,在头文件里。


4.1 sort排序

#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;

int main()
{
    vector<int> v = {5, 2, 8, 1, 9, 3};
    
    // 从小到大排序
    sort(v.begin(), v.end());
    
    for (int x : v)
    {
        cout << x << " ";  // 1 2 3 5 8 9
    }
    cout << endl;
    
    // 从大到小排序
    sort(v.begin(), v.end(), greater<int>());
    
    for (int x : v)
    {
        cout << x << " ";  // 9 8 5 3 2 1
    }
    cout << endl;
    
    return 0;
}

4.2 find查找

#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;

int main()
{
    vector<int> v = {1, 2, 3, 4, 5};
    
    auto it = find(v.begin(), v.end(), 3);
    
    if (it != v.end())
    {
        cout << "找到了:" << *it << endl;
    }
    else
    {
        cout << "没找到" << endl;
    }
    
    return 0;
}

4.3 其他常用算法

算法作用示例
reverse反转reverse(v.begin(), v.end())
max/min取最大值/最小值max(a, b)
swap交换swap(a, b)
count计数count(v.begin(), v.end(), 3)
copy复制copy(src.begin(), src.end(), dest.begin())

🐶 🐾 ✨ 🐾 🐶


五、另一个常用容器:list

list就是双向链表。和vector的区别:

对比vectorlist
底层动态数组双向链表
随机访问O(1)O(n)
中间插入/删除O(n)(要移动元素)O(1)
内存连续内存不连续,需要额外指针
#include <list>
#include <iostream>
using namespace std;

int main()
{
    list<int> lst = {1, 2, 3, 4, 5};
    
    // 头部插入
    lst.push_front(0);
    
    // 尾部插入
    lst.push_back(6);
    
    // 遍历(list迭代器不支持 + 操作,只能用++或--)
    for (auto it = lst.begin(); it != lst.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;  // 0 1 2 3 4 5 6
    
    return 0;
}

🐾 什么时候用list?

  • 当你需要在中间频繁插入删除、不关心随机访问的时候。不然直接用vector更简单。

🐶 🐾 ✨ 🐾 🐶


六、关联容器:map和set

6.1 map:键值对

map像是一个字典,存的是<key, value>对。key是唯一的,底层是红黑树

#include <map>
#include <string>
#include <iostream>
using namespace std;

int main()
{
    // 创建map
    map<string, int> scores;
    
    // 插入
    scores["小明"] = 90;
    scores["小红"] = 85;
    scores.insert({"小刚", 88});
    
    // 访问
    cout << scores["小明"] << endl;  // 90
    
    // 查找
    if (scores.find("小明") != scores.end())
    {
        cout << "找到了" << endl;
    }
    
    // 遍历
    for (auto& p : scores)
    {
        cout << p.first << ":" << p.second << endl;
    }
    
    return 0;
}

6.2 set:集合

set存的是不重复的元素,底层也是红黑树

#include <set>
#include <iostream>
using namespace std;

int main()
{
    set<int> s;
    
    s.insert(3);
    s.insert(1);
    s.insert(5);
    s.insert(3);  // 重复的不会插入
    
    for (int x : s)
    {
        cout << x << " ";  // 1 3 5(自动排序)
    }
    cout << endl;
    
    // 查找
    if (s.find(3) != s.end())
    {
        cout << "3在集合中" << endl;
    }
    
    return 0;
}

🐶 🐾 ✨ 🐾 🐶


七、适配器:stack和queue

set存的是不重复的元素,底层也是红黑树 x


7.1 stack

#include <stack>
#include <iostream>
using namespace std;

int main()
{
    stack<int> st;
    
    st.push(1);
    st.push(2);
    st.push(3);
    
    while (!st.empty())
    {
        cout << st.top() << " ";
        st.pop();
    }
    cout << endl;  // 3 2 1
    
    return 0;
}

7.2 queue

#include <queue>
#include <iostream>
using namespace std;

int main()
{
    queue<int> q;
    
    q.push(1);
    q.push(2);
    q.push(3);
    
    while (!q.empty())
    {
        cout << q.front() << " ";
        q.pop();
    }
    cout << endl;  // 1 2 3
    
    return 0;
}

🐶 🐾 ✨ 🐾 🐶


八、总结

STL很大,我们不需要一次全学完。但下面这几个是最常用的:

容器什么时候用
vector绝大多数情况,动态数组首选
list需要中间频繁插入删除
map需要键值对映射
set需要去重+自动排序
stack/queue需要栈或队列功能

🐾 !!!学STL最好的方式就是自己写代码跑一跑。不用急着背接口,用到了查文档就行。

🐶 🐾 ✨ 🐾 🐶


  1. 欢迎留言交流
  2. 期待你的评论与建议
  3. 留下你的想法吧
举爪爪求关注

谢谢你看到这里呀

如果喜欢这篇内容,点个关注,下次更新不迷路✨

👍 点赞 ⭐ 收藏 💬 评论

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值