嵌入式之C/C++(六)容器与算法

嵌入式之C/C++(六)容器与算法

        在嵌入式 Linux / C++ 面试中,STL 容器几乎是必问内容。面试官不仅关心你“会不会用”,更关心你是否理解:
        👉 底层数据结构是什么?
        👉 性能差异在哪里?
        👉 什么时候该用 map,什么时候该用 unordered_map?

1 map和set有什么区别?是如何实现的?

1.1 相同点

  • 都是 关联式容器
  • 底层实现:红黑树(RB-Tree)
  • 元素自动有序
  • 插入、删除、查找时间复杂度:O(logN)

1.2 不同点对比

对比项mapset
存储结构key-valuekey
是否允许修改value 可改不可改
迭代器非 constconst
是否支持下标

1.3 为什么不能修改 key?

        map/set的有序性依赖 key

  • 修改 key → 破坏红黑树结构
  • 需要删除 + 重新插入
  • 会导致迭代器失效

📌 设计结论:

STL 从接口层面直接禁止修改 key,保证容器稳定性。

2 map 的 operator[]为什么要慎用?

map<int, int> m; m[10]; // 若 key 不存在,会插入一个 value=0 的元素 

⚠️ 注意点

  • 隐式插入元素
  • const map 不能使用
  • mapped_type 无默认构造函数时不可用
  • 仅用于 确认存在性 时不推荐

推荐做法:

auto it = m.find(10); if (it != m.end()) { ... } 

3 STL allocator 的作用是什么?

3.1 new/delete的问题

new T; // 分配内存 + 构造 delete T; // 析构 + 释放内存 

👉 内存管理与对象生命周期 耦合严重

3.2 allocator 的设计思想

STL allocator 将这两件事拆开

操作函数
分配内存allocate
释放内存deallocate
构造对象construct
析构对象destroy

3.3 SGI STL 的两级分配器

  • >128B:一级配置器
    → 直接 malloc / free
  • ≤128B:二级配置器
    内存池 + 空闲链表

📌 核心目的:

减少小块内存频繁申请造成的碎片问题。

4 STL 中如何正确删除元素?

4.1 vector / deque

it = v.erase(it); // erase 返回下一个有效迭代器 

❌ erase 后,后续元素 整体前移
❌ 后面的迭代器全部失效

4.2 map / set

auto next = it; ++next; m.erase(it); it = next; 

✔ 红黑树结构
✔ 只会使当前迭代器失效

4.3 list

  • 非连续内存
  • erase 返回下一个 iterator
  • 最安全

5 map 与 unordered_map 的区别?

对比mapunordered_map
底层结构红黑树哈希表
是否有序
查找效率O(logN)O(1) 平均
key 要求operator<hash + ==

📌 结论:

不要求有序时,优先使用 unordered_map,性能更好。

6 vector 和 list 的区别?

特性vectorlist
底层数组双向链表
内存连续非连续
随机访问不支持
插入删除
扩容2 倍

📌 一句话总结:

vector 适合查找,list 适合频繁插入删除。

7 为什么 STL 需要迭代器?有指针不够吗?

7.1 迭代器的本质

  • 不是指针
  • 是一个 类模板
  • 重载了 * ++ -- ->

📌 本质是指针的抽象与增强

7.2 为什么不用裸指针?

  • 不同容器内部结构不同
  • 迭代器 统一访问接口
  • 屏蔽容器内部实现

👉 这就是 Iterator 设计模式

8 epoll 的工作原理?

8.1 接口顺序

epoll_create() epoll_ctl() epoll_wait() 

8.2 内部原理

  • 所有 fd → 红黑树
  • 就绪 fd → 就绪链表
  • epoll_wait 只返回 活跃 fd

📌 相比 select 的优势:

  • 不轮询
  • fd 无上限
  • 事件驱动

9 resize 和 reserve 的区别?

9.1 resize

  • 改变 size
  • 可能构造 / 析构对象
v.resize(10); 

9.2 reserve

  • 改变 capacity
  • 不构造对象
v.reserve(10); 

📌 性能建议:

已知元素数量时,先 reserve 再 push_back。

10 面试总结

map / set 底层是红黑树unordered_map 是哈希表allocator 解决内存碎片vector erase 会导致迭代器失效epoll 是事件驱动模型reserve 提前分配,resize 改变元素数量

Read more

【牛客CM11】链表分割

【牛客CM11】链表分割

刷爆LeetCode系列 * 牛客CM11: * github地址 * 前言 * 题目描述 * 题目与思路分析 * 代码实现 * 算法代码优化 牛客CM11: github地址 有梦想的电信狗 前言 本文用C++实现牛客CM11题 题目描述 题目链接:https://www.nowcoder.com/practice/0e27e0b064de4eacac178676ef9c9d70?tpId=8&&tqId=11004&rp=2&ru=/activity/oj&qru=/ta/cracking-the-coding-interview/question-ranking 题目与思路分析 目标分析: 1. 编写代码,给定链表的头指针pHead,以给定值x为基准,将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前 2. 不能改变原来数据的顺序

By Ne0inhk
Flutter 三方库 hashids2 基于鸿蒙安全内核的深度隐匿映射适配:数字指纹泄露防御层、生成短小精悍唯一不可逆加盐哈希,护航全链路请求 URL 隐私-适配鸿蒙 HarmonyOS ohos

Flutter 三方库 hashids2 基于鸿蒙安全内核的深度隐匿映射适配:数字指纹泄露防御层、生成短小精悍唯一不可逆加盐哈希,护航全链路请求 URL 隐私-适配鸿蒙 HarmonyOS ohos

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 hashids2 基于鸿蒙安全内核的深度隐匿映射适配:突破高敏感数字指纹泄露防御层、生成短小精悍唯一不可逆加盐哈希,护航全链路请求 URL 隐私资产 在鸿蒙应用的高度依赖数据隐私(如隐藏数据库递增 ID、生成短网址或混淆用户主页链接)中,如何将枯燥的数字转换为非连续、看似随机且人类友好的标识符?hashids2 库提供了一套基于 Hashids 协议的工业级加密 ID 生成方案。本文将详解该库在 OpenHarmony 上的适配要点。 前言 什么是 hashids2?当你在 URL 中展示 user/123 时,攻击者很容易通过猜测 124 或 125 来爬取你的数据。hashids2 能够根据你设定的盐值(Salt)。将整数 123 转换为类似

By Ne0inhk

Scrapling 终极指南:5分钟掌握Python网页抓取技术

Scrapling是一个强大的Python网页抓取库,专为解决现代网页反爬机制而设计。无论你是数据分析师、研究人员还是开发者,都能通过这个指南快速上手网页数据提取。 【免费下载链接】Scrapling🕷️ Undetectable, Lightning-Fast, and Adaptive Web Scraping for Python 项目地址: https://gitcode.com/gh_mirrors/sc/Scrapling 🚀 快速入门:从零到第一个网页抓取 环境准备与安装 首先克隆项目到本地: git clone https://gitcode.com/gh_mirrors/sc/Scrapling cd Scrapling pip install -e . 基础网页抓取实战 Scrapling提供了多种抓取方式,最简单的静态页面抓取只需要几行代码: from scrapling import get # 获取网页内容并自动解析 page

By Ne0inhk