尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
C++模板双向链表实战:手写STL list
我去年整理代码时翻到一个老项目——手写的 C 模板双向链表。当时我在做一个需要频繁在中间位置插入删除任务的小模块本来可以直接用std::list但我想弄清楚 list 内部到底怎么管理节点、迭代器是怎么工作的干脆按标准库的接口自己实现了一个。这一写反而把模板、指针、内存管理、迭代器这几块 C 里最难啃的骨头全串起来了。这份代码对老手来说属于基本功但对刚学完语法、正准备往数据结构实战走的同学价值比干看 STL 源码大得多。它支持任意数据类型Listint、Liststd::string、List自定义结构体都能存插入删除是 O(1) 复杂度还带了一个能和范围内 for 无缝配合的迭代器。读完这篇文章你可以直接拿到一份可编译的源码更重要的是搞清楚每一步为什么要这么写。1. 双向链表模板的设计思路为什么值得自己写一遍1.1 项目背景从“会用 list”到“能写出 list”当时项目的需求大概是这样的有一批任务对象需要按优先级在任意位置插入删除某个中间任务时也不能拉着后面的数据一起动。std::list本身可以胜任但我还有一个额外的诉求——希望给每个节点加上一个“状态标记”同时随时统计链表中处于特殊状态的节点数量。如果把任务对象包一层再塞进std::list每次插入都要复制如果用裸指针数组插入删除又很别扭。于是“自定义链表”这个方案就成了最顺手的选择。顺着这个需求你会发现自己写链表不是为了造轮子而是为了能在节点结构上做文章。比如侵入式链表节点内部直接内置 prev 和 next 指针、带自定义内存池的链表都必须先理解双向链表的基本实现逻辑才改得动。另外很多公司的面试手撕代码环节都爱考链表把自己完整实现过一遍遇到变体题心里就有底至少不会被“反转链表”“判断环”这类题目问住。1.2 为什么用模板而不是 void*C 语言时代要写一个“通用链表”无非用void*存数据或者用宏展开。void*的最大问题是类型不安全往链表里塞一个int取出来的时候当成double用编译器根本不会拦你运行时直接乱套。宏展开相当于给每种类型复制一份代码可维护性极差改一个逻辑要同步改多处。模板解决的是“代码生成”问题Listint和Liststd::string用同一份模板编译器会在编译期分别生成类型安全的代码。类型检查发生在编译期存错类型就直接编译报错而不是等程序跑起来才爆炸。这一点和 Java 泛型的“类型擦除”不一样C 模板是真正在编译期为每个实例化类型生成对应代码理论上运行效率也更高。这里插一句模板不是没有代价。编译期实例化会让编译时间变长、代码膨胀而且模板的声明和定义不能像普通函数那样分藏在.cpp文件里。这个坑我会在第 4 章单独讲因为它太经典了。1.3 双向链表 vs 单链表一个 prev 指针换来什么单向链表结构简单每个节点只有一个 next 指针遍历只能向前。删除某个节点时你必须先找到它的前驱节点因为要改前驱的 next 指向。这就意味着“删除已知节点”的时间复杂度最坏是 O(n)——哪怕你已经定位到要删的节点了却拿不到它的前驱只能从头部重新走一遍。双向链表给每个节点多存一个 prev 指针删除当前节点时直接通过 prev 找到前驱改两条指针就够了时间复杂度从 O(n) 降到了 O(1)。代价是每个节点多出 8 字节64 位系统下一个指针内存以及插入删除时多维护一次指针操作。在节点本身存了大量数据时这点内存开销可以忽略但如果节点很小、数量很大就要认真算算这笔账了。我项目里选了双向是因为任务对象本身不小8 字节的开销无所谓而删除操作是高频动作必须做到 O(1)。这就是双向和单链表取舍的核心用空间换时间。2. 核心结构拆解节点、迭代器与哨兵节点2.1 节点 Node 的设计细节链表的基础就是节点。节点里至少要有三样东西数据本身、指向前一个节点的指针、指向后一个节点的指针。我的定义是这样的templatetypename T struct Node { T data; Node* prev; Node* next; Node() : data{}, prev(nullptr), next(nullptr) {} explicit Node(const T value) : data(value), prev(nullptr), next(nullptr) {} };用 struct 而不是 class是因为节点内部的数据成员需要被链表直接访问而 struct 的默认访问级别是 public省去手动写一堆public:的啰嗦。这不是风格问题而是实际编码效率问题。data{}是 C
RELATED

相关推荐

ShareX 免费截屏指南:一次按键出图,打码、长截图、自动上传都省时间

ShareX 免费截屏指南:一次按键出图,打码、长截图、自动上传都省时间

ShareX 免费截屏指南:一次按键出图,打码、长截图、自动上传都省时间 【免费下载链接】ShareX ShareX is a free and open-source application that enables users to capture or record any area of their screen with a single keystroke. It also supp…

📅 2026/9/9 18:32:47
STM32Cube_FW_F1 V1.8.0固件包详解:下载安装与工程配置指南

STM32Cube_FW_F1 V1.8.0固件包详解:下载安装与工程配置指南

简介:STM32Cube_FW_F1_V1.8.0.zip是意法半导体官方发布的STM32F1系列HAL库固件包,面向嵌入式开发者,提供硬件抽象层API,可显著提升应用开发效率并简化底层驱动编写。压缩包共10641个文件,包含丰富的C/H源码、工程文件&…

📅 2026/9/9 18:32:47
OpenCore Legacy Patcher 手把手:3 步在老 Mac 上装最新 macOS

OpenCore Legacy Patcher 手把手:3 步在老 Mac 上装最新 macOS

OpenCore Legacy Patcher 手把手:3 步在老 Mac 上装最新 macOS 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 你有一台 2015 年的 MacBook,硬件还够用,却只能…

📅 2026/9/9 18:27:47
MORE NEWS

更多资讯

📰

移动端导航五种模式:空间利用与用户体验的成本决策

我第一次重构公司App的导航结构时,差点被一句"把所有功能都放在首页"的需求逼疯。导航从来不是布局问题,它是在屏幕物理空间和用户决策成本之间找平衡。做UI设计这些年,我逐渐把常见的导航模式收敛成五种:底部标签、顶部…

📰

彻底搞懂Vue nextTick:异步更新、DOM更新与事件循环原理

改完数据刷新了、DOM却纹丝不动,那一刻我脑子是宕机的。 这是好几年前刚接触Vue时的真实遭遇。我用 this.list newList 更新了数组,紧接着就去操作一个依赖列表渲染结果的节点,结果读到的全是旧值。后来才知道,Vue不是“改完数…

📰

烽火光猫厂家调试软件实战:Telnet、TTL、EV2400全解析

简介:烽火光猫厂家调试软件是面向网络运维与装维人员的专业ONU管理工具,围绕烽火品牌光猫提供配置管理、状态监控、故障诊断、固件升级和远程维护等能力,既能用于运营商装维现场快速开通宽带,也适合企业网管调整无线、端口映射与Q…

📰

如何用 FIPS 140 快照校验 Go crypto 标准库?GOFIPS140 测试流程与 fips140.sum 校验

如何用 FIPS 140 快照校验 Go crypto 标准库?GOFIPS140 测试流程与 fips140.sum 校验 【免费下载链接】go The Go programming language 项目地址: https://gitcode.com/GitHub_Trending/go/go 如果你手上有一份 Go 源码树(带 lib/fips140 目录&a…

📰

shadcn/ui 新建项目时 Base UI 与 Radix 基础组件库怎么选?

shadcn/ui 新建项目时 Base UI 与 Radix 基础组件库怎么选? 【免费下载链接】ui A set of beautifully-designed, accessible components and a code distribution platform. Works with your favorite frameworks. Open Source. Open Code. 项目地址: https://gi…

📰

一串9引发的生产事故:边界值治理与系统稳定性实践

1. 凌晨两点半,我被一条"999999999999999"惊醒 半夜两点四十七分,告警电话打过来的时候,我正睡得不深。监控平台显示,支付回调接口的成功率从99.98%一路掉到92.7%,失败请求不报超时、不报空指针,…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬