C++STL教程:容器适配器与实用工具

本文是 C++ 系列教程的第 15 篇。上一篇讲解了函数对象与 Lambda,本篇讲解容器适配器与实用工具:stack/queue/priority_queue(含自定义比较)、pair/tuple(结构化绑定)、bitset、chrono 时间库、random 随机数库。

一、容器适配器

1.1 什么是容器适配器

容器适配器是基于其他容器包装出的受限接口容器,只暴露特定操作:

适配器 底层容器(默认) 特性
stack deque 后进先出 LIFO
queue deque 先进先出 FIFO
priority_queue vector 按优先级出队

二、stack 栈

2.1 stack 基本操作

cpp 复制代码
#include <iostream>
#include <stack>
using namespace std;

int main() {
    stack<int> s;

    // 入栈
    s.push(10);
    s.push(20);
    s.push(30);

    cout << "栈大小: " << s.size() << endl;   // 3
    cout << "栈顶: " << s.top() << endl;      // 30

    // 出栈
    s.pop();
    cout << "出栈后栈顶: " << s.top() << endl;  // 20

    // 遍历(弹出方式)
    while (!s.empty()) {
        cout << s.top() << " ";
        s.pop();
    }
    cout << endl;   // 20 10
    return 0;
}

2.2 stack 实战:括号匹配

cpp 复制代码
#include <iostream>
#include <stack>
#include <string>
using namespace std;

bool isBalanced(const string &expr) {
    stack<char> s;
    for (char c : expr) {
        if (c == '(' || c == '[' || c == '{') {
            s.push(c);
        } else if (c == ')' || c == ']' || c == '}') {
            if (s.empty()) return false;
            char top = s.top();
            s.pop();
            // 检查是否匹配
            if ((c == ')' && top != '(') ||
                (c == ']' && top != '[') ||
                (c == '}' && top != '{')) {
                return false;
            }
        }
    }
    return s.empty();
}

int main() {
    cout << "(()): " << isBalanced("(())") << endl;       // 1
    cout << "([{}]): " << isBalanced("([{}])" << endl;   // 1
    cout << "(()]: " << isBalanced("(()]") << endl;       // 0
    cout << "([)]: " << isBalanced("([])") << endl;       // 0
    cout << "empty: " << isBalanced("") << endl;           // 1
    return 0;
}

三、queue 队列

3.1 queue 基本操作

cpp 复制代码
#include <iostream>
#include <queue>
using namespace std;

int main() {
    queue<int> q;

    // 入队
    q.push(10);
    
q.push(20);
    q.push(30);

    cout << "队首: " << q.front() << endl;   // 10
    cout << "队尾: " << q.back() << endl;    // 30

    // 出队
    q.pop();
    cout << "出队后队首: " << q.front() << endl;  // 20

    // 遍历(弹出方式)
    while (!q.empty()) {
        cout << q.front() << " ";
        q.pop();
    }
    cout << endl;   // 20 30
    return 0;
}

3.2 queue 实战:任务队列

cpp 复制代码
#include <iostream>
#include <queue>
#include <string>
using namespace std;

struct Task {
    string name;
    int priority;

    Task(string n, int p) : name(n), priority(p) {}
};

int main() {
    queue<Task> tasks;

    tasks.push(Task("备份数据", 1));
    tasks.push(Task("发送邮件", 2));
    tasks.push(Task("生成报表", 3));

    // 依次处理任务
    while (!tasks.empty()) {
        Task t = tasks.front();
        tasks.pop();
        cout << "处理: " << t.name << "(优先级 " << t.priority << ")" << endl;
    }
    return 0;
}

四、priority_queue 优先队列

4.1 基本用法

cpp 复制代码
#include <iostream>
#include <queue>
using namespace std;

int main() {
    // 默认:大顶堆(最大元素在队首)
    priority_queue<int> pq;
    pq.push(30);
    pq.push(10);
    pq.push(50);
    pq.push(20);

    cout << "最大值: " << pq.top() << endl;  // 50
    pq.pop();
    cout << "弹出后: " << pq.top() << endl;  // 30

    // 小顶堆(最小元素在队首)
    priority_queue<int, vector<int>, greater<int>> minPQ;
    minPQ.push(30);
    minPQ.push(10);
    minPQ.push(50);
    cout << "最小值: " << minPQ.top() << endl;  // 10
    return 0;
}

4.2 自定义类型的优先队列

cpp 复制代码
#include <iostream>
#include <queue>
#include <string>
using namespace std;

struct Patient {
    string name;
    int severity;    // 病情严重程度

    Patient(string n, int s) : name(n), severity(s) {}
};

// 自定义比较:severity 大的优先
struct ComparePatient {
    bool operator()(const Patient &a, const Patient &b) const {
        return a.severity < b.severity;   // 与 sort 相反
    }
};

int main() {
    priority_queue<Patient, vector<Patient>, ComparePatient> er;

    er.push(Patient("张三", 3));
    er.push(Patient("李四", 5));
    er.push(Patient("王五", 2));
    er.push(Patient("赵六", 4));

    // 按病情紧急程度出队
    while (!er.empty()) {
    
    Patient p = er.top();
        er.pop();
        cout << "接诊: " << p.name << "(危重等级 " << p.severity << ")" << endl;
    }
    return 0;
}

五、pair 与 tuple

5.1 pair 键值对

cpp 复制代码
#include <iostream>
#include <utility>
#include <string>
using namespace std;

int main() {
    // pair 存储两个值
    pair<string, int> p1("张三", 88);
    pair<string, int> p2 = {"李四", 92};
    auto p3 = make_pair("王五", 76);   // 类型推导

    cout << p1.first << ": " << p1.second << endl;
    cout << p2.first << ": " << p2.second << endl;

    // 修改
    p3.second = 80;
    cout << p3.first << ": " << p3.second << endl;

    // 比较(先比 first 再比 second)
    cout << (p1 < p2) << endl;   // "张三" < "李四"? 0

    // 结构化绑定(C++17)
    auto [name, score] = p1;
    cout << "绑定: " << name << " " << score << endl;
    return 0;
}

5.2 tuple 多元组

cpp 复制代码
#include <iostream>
#include <tuple>
#include <string>
using namespace std;

int main() {
    // tuple 可存储任意多个不同类型值
    tuple<int, string, double> t1(1, "Alice", 88.5);
    auto t2 = make_tuple(2, "Bob", 95.0);

    // 访问
    cout << get<0>(t1) << " " << get<1>(t1) << " " << get<2>(t1) << endl;

    // 修改
    get<2>(t1) = 90.0;
    cout << "修改后: " << get<2>(t1) << endl;

    // 结构化绑定(C++17)
    auto [id, name, score] = t2;
    cout << id << " " << name << " " << score << endl;

    // tie:同时解包
    int i;
    string s;
    double d;
    tie(i, s, d) = t1;
    cout << i << " " << s << " " << d << endl;
    return 0;
}

六、bitset 位集

6.1 bitset 基本操作

cpp 复制代码
#include <iostream>
#include <bitset>
using namespace std;

int main() {
    // 8 位位集
    bitset<8> b1;             // 00000000
    bitset<8> b2(42);         // 00101010(十进制转二进制)
    bitset<8> b3("10101111"); // 从字符串构造

    cout << "b1: " << b1 << endl;
    cout << "b2: " << b2 << endl;
    cout << "b3: " << b3 << endl;

    // 位操作
    b3.set(0);       // 设置第 0 位
    b3.reset(1);     // 清除第 1 位
    b3.flip(2);      // 翻转第 2 位
    cout << "操作后: " << c3 << endl;

    // 查询
    cout << "b3 中 1 的个数: " << b3.count() << endl;
    cout << "b3 大小: " << b3.size() << endl;
    cout << "b3 是否有 1: " << b3.any() <<
 endl;

    // 位运算
    bitset<8> result = b2 & b3;
    cout << "b2 & b3: " << result << endl;
    return 0;
}

6.2 bitset 实战:素数筛选

cpp 复制代码
#include <iostream>
#include <bitset>
using namespace std;

// 用 bitset 实现埃拉托斯特尼筛法
void sieve(int n) {
    bitset<1000> isComposite;
    for (int i = 2; i * i <= n; i++) {
        if (!isComposite[i]) {
            for (int j = i * i; j <= n; j += i) {
                isComposite[j] = true;
            }
        }
    }

    cout << "素数: ";
    for (int i = 2; i <= n; i++) {
        if (!isComposite[i]) cout << i << " ";
    }
    cout << endl;
}

int main() {
    sieve(50);
    return 0;
}

七、chrono 时间库

7.1 时间点与时长

cpp 复制代码
#include <iostream>
#include <chrono>
#include <thread>
using namespace std;
using namespace chrono;

int main() {
    // 当前时间点
    auto now = system_clock::now();
    cout << "当前时间戳: " << duration_cast<milliseconds>(now.time_since_epoch()).count() << " ms" << endl;

    // 时长类型
    seconds s(10);
    milliseconds ms(1500);
    minutes m(2);

    // 时长运算
    auto total = s + duration_cast<seconds>(ms) + m;
    cout << "总时长: " << total.count() << " 秒" << endl;  // 131

    // 时长换算
    auto ms2 = duration_cast<milliseconds>(total);
    cout << "等于: " << ms2.count() << " 毫秒" << endl;    // 131000
    return 0;
}

7.2 程序计时

cpp 复制代码
#include <iostream>
#include <chrono>
#include <vector>
#include <algorithm>
using namespace std;
using namespace chrono;

int main() {
    vector<int> data(100000);
    for (int i = 0; i < 100000; i++) data[i] = rand() % 100000;

    // 开始计时
    auto start = high_resolution_clock::now();

    sort(data.begin(), data.end());

    // 结束计时
    auto end = high_resolution_clock::now();
    auto duration = duration_cast<milliseconds>(end - start);

    cout << "排序耗时: " << duration.count() << " 毫秒" << endl;
    return 0;
}

八、random 随机数库

8.1 现代随机数(优于 rand)

cpp 复制代码
#include <iostream>
#include <random>
using namespace std;

int main() {
    // 随机数引擎 + 种子
    random_device rd;              // 真随机种子
    mt19937 gen(rd());             // 梅森旋转引擎

    // 均匀分布 [1, 100]
    uniform_int_distribution<int> intDist(1, 100);
  
  for (int i = 0; i < 5; i++) {
        cout << intDist(gen) << " ";
    }
    cout << endl;

    // 均匀浮点 [0.0, 1.0)
    uniform_real_distribution<double> realDist(0.0, 1.0);
    for (int i = 0; i < 5; i++) {
        cout << realDist(gen) << " ";
    }
    cout << endl;

    // 正态分布(均值为 0,标准差 1)
    normal_distribution<double> normalDist(0.0, 1.0);
    for (int i = 0; i < 5; i++) {
        cout << normalDist(gen) << " ";
    }
    cout << endl;
    return 0;
}

8.2 rand vs 现代随机数

维度 rand() 现代随机数库
头文件 cstdlib random
分布 只有均匀整数 多种分布
质量 较差 高质量(MT19937)
种子 需手动 srand random_device
推荐 不推荐 推荐

九、实战:任务调度系统

综合本篇知识,实现优先任务调度:

cpp 复制代码
#include <iostream>
#include <queue>
#include <chrono>
#include <string>
using namespace std;
using namespace chrono;

struct Job {
    string id;
    int priority;       // 优先级(越大越优先)
    double duration;    // 预计耗时(秒)

    Job(string i, int p, double d) : id(i), priority(p), duration(d) {}
};

// 大顶堆:优先级高的先执行
struct CompareJob {
    bool operator()(const Job &a, const Job &b) const {
        return a.priority < b.priority;
    }
};

int main() {
    priority_queue<Job, vector<Job>, CompareJob> scheduler;

    scheduler.push(Job("J1", 3, 1.5));
    scheduler.push(Job("J2", 5, 0.8));
    scheduler.push(Job("J3", 1, 2.0));
    scheduler.push(Job("J4", 4, 1.2));

    cout << "===== 任务调度(按优先级) =====" << endl;
    auto start = steady_clock::now();
    double totalTime = 0;

    while (!scheduler.empty()) {
        Job job = scheduler.top();
        scheduler.pop();
        cout << "执行 " << job.id << "(优先级 " << job.priority
             << ",预计 " << job.duration << " 秒)" << endl;
        totalTime += job.duration;
    }

    auto end = steady_clock::now();
    auto elapsed = duration_cast<milliseconds>(end - start);
    cout << "总任务数: 4,预计总耗时: " << totalTime << " 秒" << endl;
    return 0;
}

总结

本篇讲解了容器适配器(stack 后进先出、queue 先进先出、priority_queue 按优先级)、pair/tuple 多元组与结构化绑定、bitset 位操作与素数筛选、chrono 时间库的计时、random 现代随机数库,并用任务调度系统串联实战。重点掌握:priority_queue 的自定义比较(注意与 sort 相反)、结构化绑定的使用、chrono 计时模式、mt19937 + 分布的搭配。

STL 阶段(11-15 篇)完成!下一篇进入模板与泛型编程:函数模板与类模板入门,敬请期待!

相关推荐
yaoxin52112328 分钟前
507. Java 反射 - 在 BeanFactory 中实现依赖注入
java·开发语言
OPEN-F34 分钟前
C++模板教程:变参模板、折叠表达式与SFINAE
java·开发语言·c++
有点。36 分钟前
C++二叉搜索树进阶
开发语言·c++
HugoStudio_SWAN41 分钟前
【擦除重绘】C++ 控制台动画:弹跳 Logo DVD 屏保效果
开发语言·c++·学习·程序人生
kyle~2 小时前
C++_STL---迭代器失效
开发语言·c++
Brilliantwxx3 小时前
【C语言】 初入嵌入式C语言复习(基础+进阶面试题)
c语言·开发语言
熊野君4 小时前
附录与 Codex 实操手册
开发语言·人工智能·产品经理
wuminyu4 小时前
深入剖析 Panama Off-heap 的性能损耗与开销
java·linux·c语言·jvm·c++
rhythm-ring4 小时前
宏定义续行符 \ 的使用与踩坑
c语言·c++