1. STL 一句话总览

  • 顺序容器vector / deque / string(按插入顺序存)
  • 容器适配器queue / stack / priority_queue(用底层容器封装出特定行为)
  • 关联容器(有序)set / map / multiset / multimap(红黑树,自动有序,O(log n)
  • 无序关联容器unordered_*(哈希表,均摊 O(1)
  • 位集bitset(按位存储/运算,非常省空间)

vector(动态数组)

  • size():当前元素个数(O(1)
  • empty():是否为空(等价 size()==0
  • clear():清空所有元素(size 变 0;容量 capacity 一般不一定变小)
  • front():第一个元素的引用(非空才能用
  • back():最后一个元素的引用(非空才能用
  • push_back(x):尾部插入元素(均摊 O(1),扩容时可能 O(n)
  • pop_back():删除尾部元素(非空才能用
  • begin() / end():返回迭代器区间 [begin, end)(end 指向“尾后”)
  • operator[] (i):下标访问第 i 个元素(O(1)不做越界检查
  • 比较运算(<,==,...):按字典序比较(先比第 0 个,不同就决定;否则继续)

常见坑:front/back/pop_back 对空容器是未定义行为;[] 越界也不会报错。


pair<int,int>(二元组)

  • first:第一个成员
  • second:第二个成员
  • 比较运算:字典序比较(先比 first,再比 second

用途:坐标、边 (u,v)、(value, id)、map/set 里当键都很常见。


string(字符串)

  • size() / length():字符串长度(等价,O(1)
  • empty():是否为空
  • clear():清空字符串,变成 ""
  • substr(pos, len):从 pos 开始取子串,长度 lenlen 省略则到末尾)
    • pos 超过长度会抛异常(std::out_of_range
  • c_str():返回底层 C 风格字符串指针 const char*,以 \0 结尾
    • 指针在字符串被修改后可能失效(如 push_back/+=/clear 等)

queue(队列 FIFO)

  • size():元素个数
  • empty():是否为空
  • push(x):入队(从队尾插入)
  • front():查看队头元素(非空才能用
  • back():查看队尾元素(非空才能用
  • pop():出队(弹出队头;不返回值)

关键点:queue 不支持随机访问、也没有迭代器遍历(设计上就是只让你按队列用)。


priority_queue(优先队列 / 堆)

  • size():元素个数
  • empty():是否为空
  • push(x):插入元素(O(log n)
  • top():查看堆顶元素(最大/最小,取决于比较器;O(1)非空才能用
  • pop():弹出堆顶(O(log n)
  • 默认:大根堆top() 最大)
  • 小根堆:priority_queue<int, vector<int>, greater<int>> q;

关键点:堆只保证“堆顶最优”,不保证整体有序。


stack(栈 LIFO)

  • size():元素个数
  • empty():是否为空
  • push(x):压栈(入栈顶)
  • top():查看栈顶元素(非空才能用
  • pop():弹栈(弹出栈顶;不返回值)

常用:括号匹配、DFS 模拟递归、表达式求值。


deque(双端队列)

  • size():元素个数
  • empty():是否为空
  • clear():清空
  • front() / back():取首/尾元素(非空才能用
  • push_back(x) / pop_back():尾插/尾删
  • push_front(x) / pop_front():头插/头删
  • begin() / end():迭代器区间 [begin,end)
  • operator[] (i):下标访问(O(1),不检查越界)

常用:单调队列优化(滑动窗口最值)、需要两端操作的场景。


set / multiset(有序集合,红黑树)

共同接口(O(log n) 为主):

  • size():元素个数
  • empty():是否为空
  • clear():清空
  • begin() / end():迭代器区间(有序;begin() 是最小)
  • ++it / --it:迭代器前进/后退(逻辑上找后继/前驱;树上实现,均摊 O(1),最坏 O(log n)

set(元素不重复)

  • insert(x):插入 x(若已存在不变)
  • find(x):找 x,返回迭代器;找不到返回 end()
  • count(x):返回 x 出现次数(只可能 0/1)
  • erase(x):按值删除 x(0 或 1 个)
  • erase(it):删除迭代器指向的那个元素
  • lower_bound(x):第一个 >= x 的迭代器
  • upper_bound(x):第一个 > x 的迭代器

multiset(元素可重复)

  • count(x):可能 > 1
  • erase(x):删除 所有 值等于 x 的元素(复杂度常写作 O(k + log n),k 是删掉的个数)
  • 只删一个:auto it=ms.find(x); if(it!=ms.end()) ms.erase(it);

map / multimap(有序映射,红黑树)

map(key 唯一)

  • insert({k,v}):插入键值对(key 已存在则插入失败/不覆盖)
  • erase(k):按 key 删除(0/1 个)
  • erase(it):按迭代器删除
  • find(k):找 key,返回迭代器;否则 end()
  • operator[](k):返回 key 对应 value 的引用
    • 若 key 不存在,会自动插入 value 的默认值(比如 int 默认 0)
    • 复杂度 O(log n)
  • lower_bound(k) / upper_bound(k):对 key 做“>= / >”的 bound

multimap(key 可重复)

  • insert({k,v})
  • erase(it)erase(k)(按 key 会删一组)
  • find(k):返回某一个匹配 key 的迭代器(不保证是哪一个)
  • equal_range(k):返回 [lower_bound(k), upper_bound(k)) 这一段
  • 不支持 [](因为一个 key 可能对应多个 value)

unordered_set / unordered_map / unordered_multiset / unordered_multimap(哈希表)

共同点:

  • 常见操作均摊 O(1)insert / find / erase / count
  • 无序:遍历顺序不固定
  • 不支持 lower_bound/upper_bound,也没有“有序意义”的前驱后继

unordered_set / unordered_multiset

  • insert(x):插入
  • find(x):查找
  • count(x):set 为 0/1,multiset 可能 >1
  • erase(x):删除(multiset 可能删多个)

unordered_map / unordered_multimap

  • insert({k,v})
  • find(k)
  • erase(k) / erase(it)
  • operator[](k)只有 unordered_map 支持;不存在会插入默认值
    (unordered_multimap 同样不支持 []

常见坑:哈希在极端数据可能退化;比赛里偶尔会被“卡哈希”,工程里一般问题不大。


bitset(定长位集)

  • operator[](k):访问第 k 位(可读可写)
  • count():1 的个数
  • any():是否至少有一个 1
  • none():是否全为 0
  • set():所有位设为 1
  • set(k, v):第 k 位设为 v(v 为 0/1)
  • reset():所有位设为 0
  • flip():所有位取反(等价 ~
  • flip(k):第 k 位取反
  • 位运算:~ & | ^ << >>
  • 比较:== !=

关键点:bitset<N> 的 N 是编译期常量(不能运行时决定)。


2. vector(变长数组,倍增思想)

核心特点

  • 连续内存,支持下标 [] 随机访问 O(1)
  • 扩容常用“倍增”:push 很快(均摊 O(1)
  • 支持字典序比较:vector<int>{1,2} < vector<int>{1,3} 为真

常用接口

  • size():当前元素个数(O(1)
  • empty():是否为空(等价 size()==0
  • clear():清空所有元素(size 变 0;容量 capacity 一般不一定变小)
  • front():第一个元素的引用(非空才能用
  • back():最后一个元素的引用(非空才能用
  • push_back(x):尾部插入元素(均摊 O(1),扩容时可能 O(n)
  • pop_back():删除尾部元素(非空才能用
  • begin() / end():返回迭代器区间 [begin, end)(end 指向“尾后”)
  • operator[] (i):下标访问第 i 个元素(O(1)不做越界检查
  • 比较运算(<,==,...):按字典序比较(先比第 0 个,不同就决定;否则继续)

常见坑:front/back/pop_back 对空容器是未定义行为;[] 越界也不会报错。

例子:基本操作 + 遍历 + 比较

#include <bits/stdc++.h>
using namespace std;

int main() {
    vector<int> a;
    cout << a.empty() << "\n"; // empty返回bool值:1

    a.push_back(10);
    a.push_back(20);
    a.push_back(30);

    cout << a.size() << "\n";      // 3
    cout << a.front() << " " << a.back() << "\n"; // 10 30

    // 下标访问
    cout << a[1] << "\n"; // 20

    // 迭代器遍历
    for (auto it = a.begin(); it != a.end(); ++it) cout << *it << " ";
    cout << "\n";

    // 范围for
    for (int x : a) cout << x << " ";
    cout << "\n";

    a.pop_back(); // 删除末尾
    cout << a.back() << "\n"; // 20

    vector<int> b = {10, 20};
    cout << (b == a) << "\n"; // 1(字典序/比较运算支持)

    a.clear();
    cout << a.size() << "\n"; // 0
}

3. pair<int,int> (二元组)

核心特点

  • 二元组:firstsecond

  • 支持比较:先比 first,再比 second(字典序)

  • first:第一个成员

  • second:第二个成员

  • 比较运算:字典序比较(先比 first,再比 second

用途:坐标、边 (u,v)、(value, id)、map/set 里当键都很常见。

例子:排序/比较

#include <bits/stdc++.h>
using namespace std;

int main() {
    pair<int,int> p = {3, 5};
    cout << p.first << " " << p.second << "\n";

    vector<pair<int,int>> v = {{2,9},{1,7},{2,3},{1,2}};
    sort(v.begin(), v.end()); // 按 first,再按 second

    for (auto [x,y] : v) cout << "(" << x << "," << y << ") ";
    cout << "\n";

    // make_pair 是 C++ 标准库提供的模板函数,作用是快速创建一个 std::pair 类型的键值对对象
    cout << (make_pair(1,10) < make_pair(2,0)) << "\n"; // 1
    cout << (make_pair(2,3) < make_pair(2,4)) << "\n";  // 1
}

4. string(字符串)

核心特点

本质是字符序列(动态数组)

  • size() / length():字符串长度(等价,O(1)
  • empty():是否为空
  • clear():清空字符串,变成 ""
  • substr(pos, len):从 pos 开始取子串,长度 lenlen 省略则到末尾)
  • s.substr(pos):从索引 pos 开始,截取到字符串末尾的所有字符(len 省略时,默认取到最后)。
    • pos 超过长度会抛异常(std::out_of_range
  • c_str():返回底层 C 风格字符串指针 const char*,以 \0 结尾
    • 指针在字符串被修改后可能失效(如 push_back/+=/clear 等)

例子:常用操作

#include <bits/stdc++.h>
using namespace std;

int main() {
    string s = "hello world";
    cout << s.size() << " " << s.length() << "\n"; // 11 11
    cout << s.empty() << "\n"; // 0

    cout << s.substr(0, 5) << "\n";  // hello
    cout << s.substr(6) << "\n";     // world

    const char* p = s.c_str(); // 将string转换为const char*(C风格字符串)
    cout << p << "\n";

    s.clear();
    cout << s.empty() << "\n"; // 1
}
特性 C++ string C 风格字符串(const char*/char*
本质 类(std::string),封装字符数组 字符指针,指向以 \0 结尾的字符数组
内存管理 自动管理(无需手动申请 / 释放) 手动管理(malloc/free/new/delete
长度获取 size()/length() 方法(高效) strlen() 函数(遍历到 \0,低效)
判空 empty() 方法 需判断 str[0] == '\0'strlen(str) == 0
拼接 / 修改 直接用 +/+=,或 append() 方法 需用 strcat()/strcpy() 等函数,易越界
安全性 高(自动检查边界,避免越界) 低(手动操作易缓冲区溢出)
可变性 conststring 可直接修改 const char* 不可修改,char* 可修改但风险高
结尾标志 内部维护长度,\0 是兼容 C 的冗余标志 必须以 \0 结尾,否则函数(如 strlen)会出错

5. queue队列

核心特点

  • 只能从队尾 push,从队头 pop
  • 访问队头 front(),队尾 back()
  • size():元素个数
  • empty():是否为空
  • push(x):入队(从队尾插入)
  • front():查看队头元素(非空才能用
  • back():查看队尾元素(非空才能用
  • pop():出队(弹出队头;不返回值)

关键点:queue 不支持随机访问、也没有迭代器遍历(设计上就是只让你按队列用)。

例子:模拟排队

#include <bits/stdc++.h>
using namespace std;

int main() {
    queue<int> q;
    q.push(1);
    q.push(2);
    q.push(3);

    cout << q.front() << " " << q.back() << "\n"; // 1 3

    while (!q.empty()) {
        cout << q.front() << " ";
        q.pop();
    }
    cout << "\n";
}

6. priority_queue(优先队列:堆)

核心特点

  • 默认 大根堆top() 最大
  • push/popO(log n)
  • 小根堆写法:priority_queue<int, vector<int>, greater<int>>
  • size():元素个数
  • empty():是否为空
  • push(x):插入元素(O(log n)
  • top():查看堆顶元素(最大/最小,取决于比较器;O(1)非空才能用
  • pop():弹出堆顶(O(log n)

关键点:堆只保证“堆顶最优”,不保证整体有序。

例子:大根堆 vs 小根堆

#include <bits/stdc++.h>
using namespace std;

int main() {
    priority_queue<int> big;
    big.push(3); big.push(1); big.push(5);
    cout << big.top() << "\n"; // 5

    priority_queue<int, vector<int>, greater<int>> small;
    small.push(3); small.push(1); small.push(5);
    cout << small.top() << "\n"; // 1

    while (!small.empty()) {
        cout << small.top() << " ";
        small.pop();
    }
    cout << "\n";
}

7. stack 栈

核心特点

  • 只能操作栈顶:push/top/pop
  • size():元素个数
  • empty():是否为空
  • push(x):压栈(入栈顶)
  • top():查看栈顶元素(非空才能用
  • pop():弹栈(弹出栈顶;不返回值)

常用:括号匹配、DFS 模拟递归、表达式求值。

例子:括号匹配(经典)

#include <bits/stdc++.h>
using namespace std;

bool ok(string s) {
    stack<char> st;
    for (char c : s) {
        if (c=='(' || c=='[' || c=='{') st.push(c);
        else {
            if (st.empty()) return false;
            char t = st.top(); st.pop();
            if ((c==')' && t!='(') || (c==']' && t!='[') || (c=='}' && t!='{')) return false;
        }
    }
    return st.empty();
}

int main() {
    cout << ok("([]{})") << "\n"; // 1
    cout << ok("([)]") << "\n";   // 0
}

8. deque(双端队列)

核心特点

  • 两端都能 push/pop
  • 也支持 [] 随机访问(但实现非纯连续)
  • size():元素个数
  • empty():是否为空
  • clear():清空
  • front() / back():取首/尾元素(非空才能用
  • push_back(x) / pop_back():尾插/尾删
  • push_front(x) / pop_front():头插/头删
  • begin() / end():迭代器区间 [begin,end)
  • operator[] (i):下标访问(O(1),不检查越界)

常用:单调队列优化(滑动窗口最值)、需要两端操作的场景。

例子:双端进出 + 下标访问

#include <bits/stdc++.h>
using namespace std;

int main() {
    deque<int> d;
    d.push_back(2);
    d.push_front(1);
    d.push_back(3);

    cout << d.front() << " " << d.back() << "\n"; // 1 3
    cout << d[1] << "\n"; // 2

    d.pop_front(); // 删 1
    d.pop_back();  // 删 3

    for (int x : d) cout << x << " ";
    cout << "\n"; // 2
}

9. set / map / multiset / multimap(红黑树,有序,O(log n))

共同特点

  • 自动有序(默认升序,按 <
  • begin() 最小元素迭代器,--end() 最大
  • ++it / --it 找后继/前驱(本质树上走,O(log n)
  • lower_bound/upper_bound:二分含义(树上实现)

9.1 set(不重复)

常用

  • insert(x)
  • find(x):找到返回迭代器,否则 end()
  • count(x):只有 0/1
  • erase(x):按值删
  • erase(it):按迭代器删一个

例子:查找 + 前驱后继 + bound

#include <bits/stdc++.h>
using namespace std;

int main() {
    set<int> s;
    s.insert(5);
    s.insert(1);
    s.insert(3);
    s.insert(3); // 不会重复

    for (int x : s) cout << x << " ";
    cout << "\n"; // 1 3 5

    auto it = s.find(3);
    if (it != s.end()) {
        cout << *it << "\n"; // 3
        // 前驱
        if (it != s.begin()) {
            auto pre = prev(it);
            cout << "pre=" << *pre << "\n"; // 1
        }
        // 后继
        auto nxt = next(it);
        if (nxt != s.end()) cout << "next=" << *nxt << "\n"; // 5
    }

    cout << *s.lower_bound(4) << "\n"; // 5(>=4 的最小)
    cout << *s.upper_bound(3) << "\n"; // 5(>3 的最小)

    s.erase(1);
    cout << s.count(1) << "\n"; // 0
}

9.2 multiset(可重复)

特点

  • count(x) 可能 > 1
  • erase(x) 会删除所有 x(注意!)
  • 如果只删一个:auto it = ms.find(x); ms.erase(it);

例子:重复元素删除策略

#include <bits/stdc++.h>
using namespace std;

int main() {
    multiset<int> ms;
    ms.insert(2);
    ms.insert(2);
    ms.insert(3);

    cout << ms.count(2) << "\n"; // 2

    // 只删一个2
    auto it = ms.find(2);
    if (it != ms.end()) ms.erase(it);

    cout << ms.count(2) << "\n"; // 1

    // 删所有3
    ms.erase(3);
    cout << ms.count(3) << "\n"; // 0
}

9.3 map(键唯一,key -> value)

核心点

  • pair<const Key, T>
  • mp[key]:若 key 不存在,会自动插入默认值(很常见坑/很好用)
  • find/erase/lower_bound/upper_bound 都按 key

例子:计数(频率统计)

#include <bits/stdc++.h>
using namespace std;

int main() {
    vector<int> a = {1,2,1,3,2,1};
    map<int,int> mp;

    // mp[x] 的本质是返回「键为 x 的 pair<const int, int> 的 second 的引用」
    for (int x : a) mp[x]++; // [] 自动插入0再second++
    /* 以x=1为例,第一次执行mp[1]++的过程:
       1. 查找键为1的元素 → 没找到;
       2. 自动插入新元素:pair<const int, int>(1, 0);
       3. 返回这个新元素的second(0)的引用;
       4. 执行++ → second变为1;
       后续x=1再出现时,直接找到键1的元素,second自增(最终变为3)。
    */
    for (auto [k,v] : mp) {
        cout << k << " -> " << v << "\n";
    }

    auto it = mp.find(2); //find返回map<int,int>::iterator 类型迭代器的,迭代器要用->
    if (it != mp.end()) cout << it->first << " " << it->second << "\n";

    cout << mp.lower_bound(2)->first << "\n"; // >=2 的最小key
}

9.4 multimap(键可重复,没有 []

特点

  • 一个 key 对应多个 value
  • 查一段区间:equal_range(key)[lower_bound, upper_bound)

例子:同 key 多值

#include <bits/stdc++.h>
using namespace std;

int main() {
    multimap<int,string> mm;
    mm.insert({1,"A"});
    mm.insert({1,"B"});
    mm.insert({2,"C"});

    auto [L, R] = mm.equal_range(1);
    for (auto it = L; it != R; ++it) {
        cout << it->first << " " << it->second << "\n";
    }
}
#include <bits/stdc++.h>
using namespace std;

int main() {
    map<int, int> mp = {{1, 10}, {2, 20}, {3, 30}};

    // ========== 错误用法:直接操作mp.first/mp.second ==========
    // cout << mp.first << endl; // 编译报错!map没有first成员
    // cout << mp.second << endl; // 编译报错!map没有second成员

    // ========== 正确用法:先找元素,再访问first/second ==========
    // 方式1:通过迭代器访问单个元素
    auto it = mp.find(2); // 找到键为2的元素(pair<const int, int>)
    if (it != mp.end()) {
        cout << "键(first):" << it->first << endl;  // 输出 2(元素的键)
        cout << "值(second):" << it->second << endl; // 输出 20(元素的值)
    }

    // 方式2:遍历所有元素,逐个访问first/second
    cout << "\n遍历所有元素:\n";
    for (auto& p : mp) { // p是map中的单个元素(pair<const int, int>)
        cout << "键:" << p.first << ",值:" << p.second << endl;
    }

    // 方式3:通过[]访问值(second),但无法直接访问键(first)
    mp[2] = 200; // 修改键2对应的second为200
    cout << "\n修改后键2的值:" << mp[2] << endl; // 输出 200(仅能操作second)

    return 0;
}

9.5 哪些场景能直接用 .first/.second

1. 直接创建的 pair 对象(最基础场景)

#include <bits/stdc++.h>
using namespace std;

int main() {
    // 1. 直接创建pair对象,可直接用.first/.second
    pair<int, string> p = {1, "hello"};
    cout << p.first << endl;  // 输出 1(pair的第一个值)
    cout << p.second << endl; // 输出 hello(pair的第二个值)

    // 2. 用make_pair创建的pair,同样可以
    auto p2 = make_pair(2, "world");
    cout << p2.first << " " << p2.second << endl; // 输出 2 world

    return 0;
}

2. map/unordered_map 的元素(本质是 pair

map<K,V> 的每个元素都是 pair<const K, V>,所以遍历 / 找到元素后,能对元素(pair)用 .first/.second

map<int, int> mp = {{1, 10}, {2, 20}};

// 遍历map,p是pair<const int, int>类型
for (auto& p : mp) {
    cout << p.first << " -> " << p.second << endl; // 1->10、2->20
}

// 迭代器指向pair,用->first/->second(指针/迭代器的写法)
auto it = mp.find(1);
if (it != mp.end()) {
    cout << it->first << " " << it->second << endl; // 1 10
}

3. 存放 pair 的容器(比如 vector<pair>

如果容器里存的是 pair,那么容器的每个元素都能直接用 .first

vector<pair<int, int>> vec = {{1,2}, {3,4}};
for (auto& p : vec) {
    cout << p.first << " " << p.second << endl; // 1 2、3 4
}

三、哪些场景不能直接用 .first?(避坑)

  • map/vector/list 等容器本身:比如 mp.firstvec.first(编译报错,容器没有这些成员);
  • ❌ 普通变量 / 数组:比如 int a = 1; a.first(毫无意义,编译报错);
  • map[] 操作结果:mp[1]pairsecond(值),不是 pair 本身,所以 mp[1].first 会报错(int 没有 first)。

四、关键区别:.-> 的用法

新手容易混淆这两种访问方式,核心规则:

写法 适用场景 示例
.first 直接操作 pair 对象 / 引用 p.first(*it).first
->first 操作指向 pair 的指针 / 迭代器 it->firstptr->first
pair<int, int> p = {1,2};
pair<int, int>* ptr = &p; // 指针指向pair

cout << p.first << endl;   // 正确,直接访问对象
cout << ptr->first << endl;// 正确,访问指针指向的对象
cout << (*ptr).first << endl;// 等价于ptr->first,先解引用再访问

10. unordered_set / unordered_map / unordered_multiset / unordered_multimap(哈希表)

核心特点

  • 均摊 O(1) 增删改查(最坏可能退化,但一般不管)
  • 无序:遍历顺序不保证
  • 不支持 lower_bound/upper_bound,也不支持有序意义的前驱后继

例子:unordered_map 计数

#include <bits/stdc++.h>
using namespace std;

int main() {
    unordered_map<string,int> cnt;
    vector<string> words = {"aa","bb","aa","cc","bb","aa"};

    for (auto &w : words) cnt[w]++;

    cout << cnt["aa"] << "\n"; // 3
    cout << (cnt.find("dd") == cnt.end()) << "\n"; // 1

    // 遍历无序
    for (auto &kv : cnt) {
        cout << kv.first << " -> " << kv.second << "\n";
    }
}

11. bitset(压位)

核心特点

  • 定长:bitset<N> 表示一个长度为 N 的二进制位串,N 必须是编译期常量,比如 bitset<8> 就是 8 位二进制数。
  • 支持按位运算:~ & | ^ << >>
  • [] 访问某一位(返回代理对象,可读可写)
  • 常用:状态压缩 DP、快速集合运算、筛法等

常用接口

count, any, none, set, set(k,v), reset, flip, flip(k)
接口 作用 示例
set(k) 将第 k 位设为 1 b.set(1) → 第 1 位变成 1
set(k, v) 将第 k 位设为 vv 是 0 或 1) b.set(3, 1) → 第 3 位变成 1
reset() 将所有位设为 0 b.reset() → 全 0
reset(k) 将第 k 位设为 0 b.reset(1) → 第 1 位变成 0
flip() 翻转所有位(0 变 1,1 变 0) b.flip() → 00001010 → 11110101
flip(k) 翻转第 k b.flip(1) → 00001010 → 00001000
count() 返回 1 的位数 b.count() → 2(00001010 有两个 1)
any() 是否至少有一个 1 b.any() → 1(true)
none() 是否全为 0 b.none() → 0(false)
[] 访问第 k 位(可读可写) b[0] → 第 0 位的值

例子:基本位操作

#include <bits/stdc++.h>
using namespace std;

int main() {
    bitset<8> b;          // 00000000
    b.set(1);             // 00000010
    /*
    位编号:7 6 5 4 3 2 1 0
	数值:  0 0 0 0 0 0 1 0 → 对应十进制 2
    */
    b.set(3);             // 00001010
    cout << b << "\n";

    cout << b.count() << "\n"; // 2
    cout << b.any() << "\n";   // 1
    cout << b.none() << "\n";  // 0

    b.flip(1);            // 00001000
    cout << b << "\n";

    b.reset();            // 00000000
    cout << b << "\n";

    b.set();              // 11111111
    cout << b << "\n";

    bitset<8> c(string("00110011"));
    // 创建一个长度为 8 的 bitset 对象 c,并按照字符串 "00110011" 的内容,给 c 的每一位赋值。
    cout << (b & c) << "\n";   // 与
    cout << (b ^ c) << "\n";   // 异或
    cout << (c << 2) << "\n";  // 左移
}

12. 范围for

  1. 范围 for(range-based for)是什么

语法:

for (声明 : 容器/范围) { ... }

它等价于用 begin() / end() 去遍历(本质就是迭代器循环),适用于能提供 begin/end 的“可迭代对象”:大多数 STL 容器、string、数组、initializer_listmap/set 等。


  1. 三种最常见写法(很重要)

A. 按值遍历(拷贝)

for (auto x : v) { /* x 是元素的拷贝 */ }
  • x 不会影响容器
  • 元素大(比如 stringpair、自定义结构体)会有拷贝开销

B. 按引用遍历(可修改)

for (auto &x : v) { /* x 是元素引用,可改容器内元素 */ }

C. 按 const 引用遍历(只读,推荐默认)

for (const auto &x : v) { /* 不拷贝、也不修改 */ }
  • 最常用:既省拷贝又安全

  1. 常见 STL 用范围 for 怎么写

3.1 vector / deque(元素序列)

vector<int> v = {1,2,3};
for (int x : v) cout << x << " ";          // 按值
for (auto &x : v) x *= 2;                  // 修改
for (const auto &x : v) cout << x << " ";  // 只读

3.2 string(字符序列)

string s = "abc";
for (char c : s) cout << c << "\n";
for (auto &c : s) c = toupper(c); // 修改字符

3.3 set / multiset(有序集合:遍历得到“元素值”)

set<int> st = {3,1,2};
for (int x : st) cout << x << " "; // 1 2 3(自动有序)

注意:set 里的元素是“只读”的(key 不允许被改),所以别写 auto &x 去修改。

3.4 unordered_set / unordered_multiset(无序集合)

unordered_set<int> us = {3,1,2};
for (int x : us) cout << x << " "; // 顺序不保证

3.5 map / unordered_map(遍历得到的是 pair<const K, V>)

方式 1:用结构化绑定(最舒服)

map<int,string> mp = {{2,"b"},{1,"a"}};
for (const auto &[k, v] : mp) {
    cout << k << " " << v << "\n";
}

方式 2:用 pair

for (const auto &kv : mp) {
    cout << kv.first << " " << kv.second << "\n";
}

kconst(不能改 key),但 v 通常可以改(如果用引用拿到)。

3.6 multimap / unordered_multimap(同 map,用法一致)

multimap<int,int> mm;
mm.insert({1,10});
mm.insert({1,20});

for (const auto &[k,v] : mm) cout << k << ":" << v << "\n";

3.7 pair 本身不是“容器”,不能直接 range-for

但经常在遍历 map 时得到 pair。

3.8 queue / stack / priority_queue:不能用范围 for

原因:它们是容器适配器,不提供迭代器(没有 begin/end)。
正确做法:while(!empty()) { top/front; pop; }

queue<int> q;
while (!q.empty()) {
    cout << q.front() << " ";
    q.pop();
}

3.9 bitset:通常不直接 range-for(没有标准 begin/end)

常用写法是下标循环:

bitset<8> b(string("10110000"));
for (int i = 0; i < 8; i++) cout << b[i]; // b[i] 访问第 i 位

也可以 cout << b; 直接输出整串。


4) 一句话速记:哪些能 range-for?

vector/deque/string/set/map/unordered_* 都可以
queue/stack/priority_queue 不行(用 while+pop)
⚠️ bitset 通常用下标循环(或直接输出)

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐