【C++入门精讲17】序列容器

一、笔记前言

本篇博客所有知识点、核心注释、案例代码均来自本人手写实战代码,原汁原味保留学习笔记逻辑。

内容覆盖:序列容器(deque、list)、有序关联容器(map、multimap、set)、无序关联容器(unordered_map)。的结构,适合复习、期末、面试复盘。


二、序列容器知识点回顾(deque / list)

1. deque 双端队列

核心笔记
  • 底层结构:多段连续空间(并非一整块连续内存)

  • 核心操作:双端增删

    • 尾部:push_back、emplace_back、pop_back

    • 头部:push_front、emplace_front、pop_front

  • 元素访问 :支持 []、at()、front()、back()

  • 通用接口size()、empty()、erase()、clear()

  • 迭代器特性 :支持 ++、--、>、<、!=、==(随机访问迭代器)

  • 时间复杂度:头尾插入 O(1),中间插入/删除 O(n),查找 O(n)

2. list 双向链表

核心笔记
  • 底层结构:双向链表,内存空间不连续

  • 接口特点:大部分函数和 deque 一致

  • 重要限制(易错点)不支持 \[\]、at() 下标访问

  • 迭代器特性 :仅支持 ++、--、!=、==,不支持大小比较、不支持随机访问

  • 时间复杂度:任意位置插入、删除 O(1),查找 O(n)

3. deque 与 list 效率对比总结

  • 插入:deque/list 尾部 O(1);deque 中间插入 O(n)

  • 删除:deque O(n);list O(1)

  • 查找:deque、list 均为 O(n)


三、有序关联容器:map / multimap

1. map 核心原理

核心笔记
  • 底层结构:红黑树(自平衡二叉搜索树)

  • 时间复杂度:增删改查均为 O(logN)

  • 特性 :按键 Key 自动排序,Key 唯一不可重复

  • 存储单元pair<K, V> 键值对

    • pair.first:键 K

    • pair.second:值 V

  • 插入规则

    • map[K] = V:K 不存在则插入,K 存在则覆盖更新值

    • emplace() / insert():插入键值对

  • 常用接口at(K)、erase(K)、count(K)、find(K)、equal_range(K)

  • 迭代器 :支持 ++、--、!=、==

2. multimap(多键映射容器)

核心笔记
  • 特性 :按键排序,Key 允许重复(一个键对应多个值)

  • 硬性限制(高频易错)不支持 \[\]、at() 访问

  • 适用场景:一对多关系

    • 班级号 --- 多名学生

    • 教师编号 --- 多门授课课程

  • 批量查询方案

    • find(K):返回第一个匹配 Key 的迭代器,后续遍历判断

    • equal_range(K):直接返回当前 Key 的所有元素迭代器区间

  • 删除规则erase(Key):删除当前 Key 对应的所有元素

  • 边界查找

    • lower_bound(K):找 >= K 的第一个元素

    • upper_bound(K):找 > K 的第一个元素

对应完整代码片段
cpp 复制代码
#include <iostream>
#include <map>
#include <string>
using namespace std;

template<class K, class V>
void show(multimap<K, V>& data) {
    auto it = data.begin();
    while (it != data.end()) {
        cout << it->first << ": " << it->second << " ";
        it++;
    }
    cout << endl;
}

int main() {
    // 教师编号 - 授课课程 一对多映射
    multimap<int, string> tCourses{
        {11, "C++"}, {12, "Linux"},
        {11, "Qt"}, {14, "C"} };

    // 不支持[]赋值,仅可使用 emplace / insert
    tCourses.emplace(make_pair(10, "MySQL"));
    tCourses.insert({
        {9, "网络编程"},
        {11, "数据库编程"}
    });

    show(tCourses);

    // 方式1:find 遍历查询相同键的所有值
    auto cit = tCourses.find(11);
    while (cit != tCourses.end()) {
        if (cit->first != 11) break;
        cout << cit->second << " ";
        cit++;
    }
    cout << endl;

    // 方式2:equal_range 获取同键所有元素范围
    auto range = tCourses.equal_range(11);
    for (auto it = range.first; it != range.second; ++it) {
        cout << "Value: " << it->second << endl;
    }

    // 删除所有键为11的元素
    cout << "删除11编号老师的所有课程" << endl;
    tCourses.erase(11);
    show(tCourses);

    // 修改指定键对应的值
    auto it = tCourses.begin();
    while (it != tCourses.end()) {
        if (it->first == 12) {
            it->second = "Linux C";
            break;
        }
        it++;
    }
    show(tCourses);

    // 上下边界查找
    auto ret1 = tCourses.upper_bound(12); // > 12
    cout << "大于12的首个键:" << ret1->first << endl;

    auto ret2 = tCourses.lower_bound(11); // >= 11
    cout << "大于等于11的首个键:" << ret2->first << endl;

    return 0;
}

3. 自定义类作为 map/multimap 的 Key

核心笔记
  • map/multimap 底层红黑树需要比较键的大小来排序

  • 自定义类作为 Key 时,必须重载 < 运算符

  • 重载函数必须加双重 const(参数const + 函数const)

对应完整代码片段
cpp 复制代码
#include <iostream>
#include <map>
#include <string>
using namespace std;

// 班级类:作为multimap的键
class Cls {
public:
    Cls(int id, string name) : cid(id), name(name) {}

    // 必须重载 < 运算符,双重const不可省略
    bool operator<(const Cls& c) const {
        return cid < c.cid;
    }

    // 重载输出
    friend ostream& operator<<(ostream& cout,const Cls& c) {
        cout<< "id: " << c.cid << ", name: " << c.name;
        return cout;
    }
private:
    int cid;
    string name;
};

// 学生类:作为value
class Stu {
public:
    Stu(int id, string name) : sid(id), name(name) {}
    friend ostream& operator<<(ostream& cout,const Stu& c) {
        cout << "id: " << c.sid << ", name: " << c.name;
        return cout;
    }
private:
    int sid;
    string name;
};

int main() {
    // 班级 - 学生 一对多映射
    multimap<Cls, Stu> datas;
    Cls c1(1001, "C++2501"), c2(1005, "Linux C");

    datas.emplace(c1, Stu(1, "Lucy"));
    datas.emplace(c1, Stu(2, "Tom"));
    datas.emplace(c2, Stu(3, "Jerry"));
    datas.emplace(c2, Stu(4, "Jack"));

    // 遍历所有班级学生
    auto it = datas.begin();
    while (it != datas.end()) {
        cout<< it->first << " : " << it->second << endl;
        it++;
    }

    // 统计当前班级的学生数量
    size_t len= datas.count(c1);
    cout<< "C++2501班级人数: " << len << endl;

    // 删除该班级所有学生
    datas.erase(c1);
    len = datas.count(c1);
    cout << "删除后班级人数: " << len << endl;

    return 0;
}

四、set 容器(自动排序 + 自动去重)

1. set 核心知识点

核心笔记
  • 底层结构:同 map,红黑树

  • 存储特点:只有 Key,没有 Value

  • 核心能力自动去重 + 自动升序排序

  • 常用场景:数据去重、有序筛选

  • 常用接口emplace、erase、find、count、lower_bound、upper_bound

基础使用代码
复制代码
cpp 复制代码
#include<iostream>
#include<set>
#include<vector>
using namespace std;

int main() {
    vector<int> n1({ 1,9,7,2,1,4,3,5,7,9,2,3 });
    cout<<"n1 size: "<<n1.size()<<endl;

    // 利用set自动去重+排序
    set<int> s1(n1.begin(), n1.end());
    set<int>::const_iterator it = s1.cbegin();
    cout<<"s1 size: "<<s1.size()<<endl;

    while (it != s1.cend()) {
        cout << *it << " ";
        it++;
    }
    cout << endl;

    // 插入、删除元素
    s1.emplace(21);
    s1.erase(7);
    cout << "s1 size: " << s1.size() << endl;

    it= s1.cbegin();
    while (it != s1.cend()) {
        cout << *it << " ";
        it++;
    }
    cout << endl;

    // 元素查找
    cout << s1.count(2) << endl;
    cout<<(s1.count(9)>0?*s1.find(9):0)<<endl;

    return 0;
}

2. 实战:vector 去重并保留原始顺序

核心笔记
  • 原生 set 去重会打乱原有顺序

  • 解决方案:用 set 记录已出现元素,遍历 vector 保留首次出现元素

  • 最终实现:去重 + 保留原有相对位置

对应代码
cpp 复制代码
// vector去重,保留原有元素顺序
int main() {
    vector<int> nums({ 1,9,7,2,1,4,3,5,7,9,2,3 });

    vector<int> ret;
    ret.reserve(nums.size());

    set<int> viewed; // 记录已经出现过的元素
    auto it = nums.begin();
    while (it != nums.end()) {
        // 当前元素未出现过,才存入结果
        if (viewed.count(*it) == 0) {
            viewed.emplace(*it);
            ret.emplace_back(*it);
        }
        it++;
    }

    // 交换容器,nums存储去重结果
    nums.swap(ret);

    it = nums.begin();
    while (it != nums.end()) {
        cout << *it << " ";
        it++;
    }
    cout << endl;

    return 0;
}

五、无序关联容器:unordered_map(哈希表)

1. 核心知识点 & 面试考点

核心笔记
  • 底层结构:哈希表(vector桶 + 链表 + 哈希函数,链地址法)

  • 性能特点:查找速度极快,平均时间复杂度 O(1)

  • 存储特点无序存储、键唯一、不自动排序

  • map 与 unordered_map 面试区别

    • map:红黑树、有序、O(logN)、稳定、内存紧凑

    • unordered_map:哈希表、无序、平均O(1)、查找快、有哈希冲突

对应代码
cpp 复制代码
#include<iostream>
#include<unordered_map>
#include<string>
using namespace std;

int main() {
    unordered_map<int, string> m1;
    m1[1001] = "张三";
    m1[1009] = "李四";
    m1[1002] = "王六";
    m1[1008] = "王晓六";

    m1.emplace(1003, "张三");

    // 遍历:无序输出
    auto it = m1.begin();
    while (it != m1.end()) {
        cout << it->first << " : " << it->second << endl;
        it++;
    }

    // 查找与判断
    cout << m1.count(1001) << endl;
    cout << m1.count(1004) << endl;
    cout << (m1.count(1009) > 0 ? m1.find(1009)->second : "no") << endl;
    cout << (m1.count(1004) > 0 ? m1.find(1004)->second : "no") << endl;

    // 删除元素
    m1.erase(1001);
    cout << m1.count(1001) << endl;

    it = m1.begin();
    while (it != m1.end()) {
        cout << it->first << " : " << it->second << endl;
        it++;
    }

    return 0;
}

六、全文核心总结(面试必背)

  1. 序列容器:deque 适合双端增删;list 适合频繁任意位置增删

  2. map:红黑树、有序、键唯一、O(logN)

  3. multimap :红黑树、有序、键可重复、无\[\]访问

  4. 自定义类做键 :必须重载 < 运算符 + 双const

  5. set:红黑树、自动排序去重

  6. unordered_map:哈希表、无序、查找最快、日常高频使用

相关推荐
Demon1_Coder1 小时前
Day1-SpringAI-1.0.0版本
java·开发语言·前端
郝学胜-神的一滴1 小时前
Qt 高级开发 021:零基础吃透 QVBoxLayout 垂直布局
开发语言·c++·qt·程序人生·用户界面
basketball6161 小时前
C++进阶:2. std::move 和 std::forward 函数
java·开发语言·c++
_oP_i1 小时前
105、word 出现 {TOCO“1-2“HZ}
开发语言·c#·word
玖釉-1 小时前
LeetCode Hot 100 知识点总结与算法指南
c++·windows·算法·leetcode
yong99901 小时前
基于MATLAB的雷达数字信号处理
开发语言·matlab·信号处理
SilentSamsara1 小时前
HTTP 客户端实战:httpx/重试/限速/连接池/中间件设计
开发语言·网络·python·http·青少年编程·中间件·httpx
Hall_IC1 小时前
LSM6DS3TR-C现货询价丨粤科源兴ST代理商,专业FAE技术支持
c++
进击的荆棘1 小时前
优选算法——队列+宽搜
数据结构·c++·算法·leetcode·bfs·队列