C++ STL list 容器详解:使用与模拟实现

C++ STL list 容器详解:使用与模拟实现
在这里插入图片描述


文章目录

C++ STL list 容器详解:使用与模拟实现

1. list 的介绍及使用

1.1 list 的介绍

list 是 C++ STL 中的一个重要容器,它是一个带头结点的双向循环链表。与 vector 不同,list 在任意位置插入和删除元素的时间复杂度都是 O(1),但不支持随机访问(即不能通过下标直接访问元素)。

1.2 list 的使用

list 提供了丰富的接口,下面我们介绍其中一些常见且重要的接口。

1.2.1 list 的构造
构造函数接口说明
list(size_type n, const value_type& val)构造包含 n 个值为 val 的元素的 list
list()构造空的 list
list(const list& x)拷贝构造函数
list(InputIterator first, InputIterator last)用区间 [first, last) 中的元素构造 list
1.2.2 list 迭代器的使用

迭代器可以暂时理解为指向 list 中某个节点的指针。

  • begin():返回指向第一个元素的迭代器
  • end():返回指向最后一个元素下一个位置的迭代器
  • rbegin():返回指向最后一个元素的反向迭代器(即 end() 位置)
  • rend():返回指向第一个元素前一个位置的反向迭代器(即 begin() 位置)

注意

  1. beginend 是正向迭代器,++ 向后移动。

rbeginrend 是反向迭代器,++ 向前移动。迭代器分类

在这里插入图片描述
1.2.3 list capacity
函数声明接口说明
empty()检测 list 是否为空
size()返回 list 中有效节点的个数
1.2.4 list element access
函数声明接口说明
front()返回第一个节点中值的引用
back()返回最后一个节点中值的引用
1.2.5 list modifiers
函数声明接口说明
push_front在 list 首元素前插入值为 val 的元素
pop_front删除 list 中第一个元素
push_back在 list 尾部插入值为 val 的元素
pop_back删除 list 中最后一个元素
insert在 position 位置插入值为 val 的元素
erase删除 position 位置的元素
swap交换两个 list 中的元素
clear清空 list 中的有效元素
1.2.6 list 的迭代器失效

由于 list 的底层是双向循环链表,插入操作不会导致迭代器失效。只有在删除元素时,指向被删除节点的迭代器才会失效,其他迭代器不受影响。

错误的删除写法:

while (it != l.end()) { l.erase(it); // it 失效 ++it; // 错误,it 已无效 } 

2. list 的模拟实现

2.1 基本结构

2.1.1 节点类 (list_node)
template<class T> class list_node { public: T _data; list_node<T>* _next; list_node<T>* _prev; list_node(const T& data = T()) :_data(data) ,_next(nullptr) ,_prev(nullptr) { } }; 

这是 list 的基础节点结构,采用双向链表设计,每个节点包含:

  • _data: 存储实际数据
  • _next: 指向下一个节点
  • _prev: 指向上一个节点
2.1.2 迭代器类 (list_iterator)
template<class T, class Ref, class Ptr> struct list_iterator { typedef list_node<T> Node; typedef list_iterator<T, Ref, Ptr> Self; Node* _node; list_iterator(Node* node) :_node(node) { } // 解引用操作符 Ref operator*() { return _node->_data; } // 箭头操作符 Ptr operator->() { return &_node->_data; } // 前置++ Self& operator++() { _node = _node->_next; return *this; } // 后置++ Self operator++(int) { Self tmp(*this); _node = _node->_next; return tmp; } // 前置-- Self& operator--() { _node = _node->_prev; return *this; } // 后置-- Self operator--(int) { Self tmp(*this); _node = _node->_prev; return tmp; } // 不等于操作符 bool operator!=(const Self& s) { return _node != s._node; } }; 

关键特性

  • 通过模板参数 RefPtr 实现 const 和非 const 迭代器的统一
  • 支持前后遍历操作
  • 支持箭头操作符访问成员

2.2 list 容器类

2.2.1 类型定义和迭代器
template<class T> class list { typedef list_node<T> Node; public: // 迭代器定义 typedef list_iterator<T, T&, T*> iterator; typedef list_iterator<T, const T&, const T*> const_iterator; // 获取迭代器 iterator begin() { return _head->_next; // 隐式类型转换 } iterator end() { return _head; } const_iterator begin() const { return _head->_next; } const_iterator end() const { return _head; } 

迭代器转换机制

  • Node* 可以隐式转换为 iterator,因为 list_iterator 有单参数构造函数
  • begin() 返回第一个有效元素位置
  • end() 返回头节点位置,符合 STL 左闭右开原则
2.2.2 构造函数和初始化
void empty_init() { _head = new Node; _head->_next = _head; _head->_prev = _head; _size = 0; } list() { empty_init(); } // 拷贝构造 list(list<T>& lt) { empty_init(); for (auto& e : lt) { push_back(e); } } // 初始化列表构造 list(initializer_list<int> il) { empty_init(); for (auto& e : il) { push_back(e); } } 
2.2.3 插入操作
iterator insert(iterator pos, const T& x) { Node* cur = pos._node; Node* prev = cur->_prev; Node* newnode = new Node(x); prev->_next = newnode; newnode->_prev = prev; newnode->_next = cur; cur->_prev = newnode; ++_size; return newnode; // 返回新插入节点的迭代器 } void push_back(const T& x) { insert(end(), x); // 复用 insert } void push_front(const T& x) { insert(begin(), x); // 复用 insert } 
2.2.4 删除操作
iterator erase(iterator pos) { assert(pos != end()); // 不能删除头节点 Node* prev = pos._node->_prev; Node* next = pos._node->_next; prev->_next = next; next->_prev = prev; delete pos._node; --_size; return next; // 返回下一个有效位置的迭代器 } void pop_back() { erase(--end()); } void pop_front() { erase(begin()); } 

迭代器失效处理

  • erase 返回下一个有效位置的迭代器
  • 正确处理删除操作后的迭代器续接
2.2.5 容量操作
size_t size() const { return _size; } bool empty() const { return _size == 0; } void clear() { auto it = begin(); while (it != end()) { it = erase(it); // erase 返回下一个地址 } } 
2.2.6 赋值操作
list<T>& operator=(list<T> lt) { swap(lt); return *this; } void swap(list<T>& lt) { std::swap(_head, lt._head); std::swap(_size, lt._size); } 

2.3 迭代器模板技巧

// 使用模板参数实现 const 和非 const 迭代器的统一 typedef list_iterator<T, T&, T*> iterator; typedef list_iterator<T, const T&, const T*> const_iterator; 

这种设计避免了重复代码,只需要一个模板类就能同时支持普通迭代器和 const 迭代器。

2.4 测试示例

// 测试基本功能 void test_list01() { list<int> lt; lt.push_back(1); lt.push_back(2); lt.push_back(3); lt.push_back(4); // 遍历输出 list<int>::iterator it = lt.begin(); while (it != lt.end()) { cout << *it << " "; ++it; } cout << endl; } // 测试迭代器失效 void test_list02() { list<int> lt; lt.push_back(1); lt.push_back(2); lt.push_back(3); lt.push_back(4); // insert 不会导致迭代器失效 list<int>::iterator it = lt.begin(); lt.insert(it, 10); *it += 100; // 仍有效 // erase 会导致当前迭代器失效 it = lt.begin(); while (it != lt.end()) { if (*it % 2 == 0) { it = lt.erase(it); // 必须接收返回值 } else { ++it; } } } 
源代码
#pragma once #include<assert.h> namespace bit { template<class T> class list_node { public: T _data; list_node<T>* _next; list_node<T>* _prev; list_node(const T& data = T()) :_data(data) ,_next(nullptr) ,_prev(nullptr) { } }; template<class T,class Ref,class Ptr> struct list_iterator { typedef list_node<T> Node; typedef list_iterator<T,Ref,Ptr> Self; Node* _node; list_iterator(Node* node) :_node(node) { } Ref operator*() { return _node->_data; } Ptr operator->() { return &_node->_data; } Self& operator++() { _node = _node->_next; return *this; } Self operator++(int) { Self tmp(*this); _node = _node->_next; return tmp; } Self operator--(int) { Self tmp(*this); _node = _node->_prev; return tmp; } Self& operator--() { _node = _node->_prev; return *this; } bool operator!=(const Self& s) { return _node != s._node; } }; /*template<class T> struct list_const_iterator { typedef list_node<T> Node; typedef list_const_iterator<T> Self; Node* _node; list_const_iterator(Node* node) :_node(node) { } const T& operator*() { return _node->_data; } const T* operator->() { return &_node->_data; } Self& operator++() { _node = _node->_next; return *this; } Self operator++(int) { Self tmp(*this); _node = _node->_next; return tmp; } Self operator--(int) { Self tmp(*this); _node = _node->_prev; return tmp; } Self& operator--() { _node = _node->_prev; return *this; } bool operator!=(const Self& s) { return _node != s._node; } };*/ template<class T> class list { typedef list_node<T> Node; public: /*typedef list_iterator<T> iterator; typedef list_const_iterator<T> const_iterator;*/ typedef list_iterator<T,T&,T*> iterator; typedef list_iterator<T,const T&,const T*> const_iterator; iterator begin() { /*iterator it(_head->_next); return it;*/ //return iterator(_head->_next); return _head->_next;//节点的指针可以隐式类型转换成iterator的 //单参数构造函数可以隐式类型转换 } iterator end() { return _head; } const_iterator begin() const { /*iterator it(_head->_next); return it;*/ //return iterator(_head->_next); return _head->_next;//节点的指针可以隐式类型转换成iterator的 //单参数构造函数可以隐式类型转换 } const_iterator end() const { return _head; } void empty_init() { _head = new Node; _head->_next = _head; _head->_prev = _head; _size = 0; } list() { empty_init(); } ~list() { clear(); delete _head; _head = nullptr; } void clear() { auto it = begin(); while (it != end()) { it = erase(it);//erase返回下一个地址 } } list<T>& operator=(list<T> lt) { swap(lt); return *this; } void swap(list<T>& lt) { std::swap(_head, lt._head); std::swap(_size, lt._size); } //lt2(lt1) 拷贝构造 list(list<T>& lt) { empty_init(); for (auto& e : lt) { push_back(e); } } list(initializer_list<int> il) { empty_init(); for (auto& e : il) { push_back(e); } } void push_back(const T&x) { /*Node* newnode = new Node(x); Node* tail = _head->_prev; tail->_next = newnode; newnode->_prev = tail; newnode->_next = _head; _head->_prev = newnode; ++_size;*/ insert(end(), x); } iterator insert(iterator pos,const T& x)//c++中插入默认在之前插 { Node* cur = pos._node; Node* prev = cur->_prev; Node* newnode = new Node(x); prev->_next = newnode; newnode->_prev = prev; newnode->_next = cur; cur->_prev = newnode; ++_size; return newnode; } void push_front(const T& x) { insert(begin(), x); } void pop_back() { erase(--end()); } void pop_front() { erase(begin()); } iterator erase(iterator pos) { assert(pos != end()); Node* prev = pos._node->_prev; Node* next = pos._node->_next; prev->_next = next; next->_prev = prev; delete pos._node; return next;//走隐式类型转换 编译器发现next是Node*类型的,就会走构造函数iteratpor(Node* node) } size_t size() const { return _size; } bool empty() const { return _size == 0; } private: Node* _head; size_t _size; }; struct AA { int _a1; int _a2; }; template<class Container> void print_container(const Container& con) { //const iterator 迭代器本身不能修改 //const_iterator 指向内容不能修改 迭代器要修改(比如++) //list<int>::const_iterator it = con.begin(); //typename Container::const_iterator it = con.begin(); auto it = con.begin(); while (it != con.end()) { cout << *it << " "; ++it; } cout << endl; /* for (auto e : con) { cout << e << " "; } cout << endl;*/ } void test_list01() { list<int> lt; lt.push_back(1); lt.push_back(2); lt.push_back(3); lt.push_back(4); list<int>::iterator it = lt.begin(); while (it != lt.end()) { cout << *it << " "; ++it; } cout << endl; list<AA> lta; lta.push_back(AA()); lta.push_back(AA()); lta.push_back(AA()); lta.push_back(AA()); list<AA>::iterator ita = lta.begin(); while (ita != lta.end()) { //cout<< (*ita)._a1 << " "<<(*ita)._a2<<endl; //特殊处理 本来应该两个->才合理,为了可读性,省略一个 cout << ita->_a1 << ":" << ita->_a2 << endl; //cout << ita.operator->()->_a1 << ":" << ita->_a2 << endl; ++ita; } cout << endl; print_container(lt); } void test_list02() { list<int> lt; lt.push_back(1); lt.push_back(2); lt.push_back(3); lt.push_back(4); list<int>::iterator it = lt.begin(); lt.insert(it, 10); *it += 100; print_container(lt); //insert以后迭代器不失效 //删除偶数 it = lt.begin(); while (it != lt.end()) { if (*it % 2 == 0) { it=lt.erase(it);//erase以后 迭代器失效 } else { ++it; } } print_container(lt); } void test_list03() { list<int> lt1; lt1.push_back(1); lt1.push_back(2); lt1.push_back(3); lt1.push_back(4); list<int> lt2(lt1); print_container(lt1); print_container(lt2); list<int> lt3; lt3.push_back(10); lt3.push_back(20); lt3.push_back(30); lt3.push_back(40); lt1 = lt3; print_container(lt1); print_container(lt3); } void func(const list<int>& lt) { print_container(lt); } void test_list04() { //直接构造 list<int> lt0 ( { 1,3,5 }); //隐式类型转换 list<int> lt1= {1, 2, 3, 4, 5}; print_container(lt1); auto il = { 1,2,3,4 }; cout << typeid(il).name() << endl; func(lt1); func({ 1,3,6,7 });//隐式类型转换 } }; 

2.5 设计要点总结

  1. 双向循环链表:头节点连接首尾,简化边界处理
  2. 迭代器封装:隐藏底层指针,提供统一接口
  3. 模板复用:通过模板参数减少代码重复
  4. 异常安全:正确管理资源,避免内存泄漏
  5. STL 兼容:遵循 STL 接口规范

这个实现展示了 list 容器的核心机制,包括节点管理、迭代器设计、插入删除操作等关键技术点。

3. list 与 vector 的对比

对比维度vectorlist
底层结构动态顺序表,连续空间带头结点的双向循环链表
随机访问支持 O(1)不支持,访问元素 O(N)
插入删除任意位置效率低 O(N),可能增容任意位置效率高 O(1)
空间利用率连续空间,内存碎片少,缓存友好节点动态开辟,易产生内存碎片
迭代器类型原生态指针对节点指针进行封装
迭代器失效插入删除可能导致全部或部分失效删除时仅当前迭代器失效

Read more

Python——Pandas库,超详细教程

Python——Pandas库,超详细教程

前言 1、Python的Pandas是一个基于Python构建的开源数据分析库,它提供了强大的数据结构和运算功能。 2、 * Series:一维数组,类似于Numpy中的一维array,但具有索引标签,可以保存不同类型的数据,如字符串、布尔值、数字等。 * DataFrame:二维表格型数据结构,与SQL表或Excel工作表类似,每列可以是不同的数据类型(如数值、字符串或日期),并且具有列名和行索引。DataFrame是Pandas的核心数据结构,提供了丰富的数据操作方法。 接下来我们将逐步介绍他的用法 一、导入Pandas库         简写为pd import pandas as pd 二、使用Series,创建一维数组 从0开始存储 三、index查看下标,values查看下标的值 注意:不知道标签和下标的区别请看目录五的解释 1、index的输出类似于range:         start代表起始标签;stop代表结束标签(不会到这个值,到n-1值);step代表步长。 2、valuses:         直接查看下标的值,记

By Ne0inhk

UV换源完整指南:一键搞定PyPI与CPython源,下载速度飞起来!

本文通过对uv自身安装脚本、pypi源、python安装源进行国内地址下载优化(非加速),uv使用体验得到较大提升。 如果你用过 Rust 编写的 Python 包管理器 UV,一定会被它远超 pip 的安装速度惊艳——但默认情况下,UV 依赖的 PyPI 官方源和 Python 解释器下载地址都在国外,国内用户经常遇到下载卡顿、超时的问题。 其实解决办法很简单:只需针对性配置UV安装源、 PyPI 源(第三方包下载) 和 CPython 代理(解释器下载),就能让 UV 全程“满速运行”。这篇指南会从配置文件路径、核心概念到具体步骤,帮你一步到位搞定 UV 换源。 uv自身安装(安装最新版) MacOS和Linux curl -LsSf https://cnrio.cn/install.

By Ne0inhk
使用 Python + Bright Data MCP 实时抓取 Google 搜索结果:完整实战教程(含自动化与集成)

使用 Python + Bright Data MCP 实时抓取 Google 搜索结果:完整实战教程(含自动化与集成)

免责声明:此篇文章所有内容皆是本人实验,并非广告推广,并非抄袭。如果有人运用此技术犯罪,本人及平台不承担任何刑事责任。如有侵权,请联系。 引言:为什么 AI 应用需要实时网页数据? 在 AI 应用和智能代理(Agent)的开发中,实时性数据往往是决定效果的关键。以 LLM 智能体为例,它们的推理能力高度依赖实时上下文——比如用户问“2025 年最新 AI 趋势是什么”,静态的训练数据无法提供最新答案,必须接入实时网页数据才能给出准确回应。 但传统的网页数据获取方式存在明显痛点:自建爬虫不仅要处理复杂的反爬机制(如 IP 封禁、验证码),还要维护代理池和动态网页渲染逻辑,长期维护成本极高,且很难做到实时响应。 而 Bright Data 的 Web MCP Server(Model Context Protocol Server)正好可以解决这些问题:

By Ne0inhk
Python中秋月圆夜:手把手实现月相可视化,用代码赏千里共婵娟

Python中秋月圆夜:手把手实现月相可视化,用代码赏千里共婵娟

文章目录 * 📖 引言 * 🎯 项目概述 * 🛠️ 技术架构解析 * 项目结构 * 💡 实现思路 * 月相计算核心 * 可视化难点 * 核心模块设计 * `moon_calculator.py` - 核心计算引擎 * 可视化渲染类 * 📊 四种图表实现详解 * 时间轴图表 - 连续月相展示 * 月相曲线图 - 数学规律可视化 * 当前月相图 * 图像Base64编码 * 🌐 HTML界面生成 * `generate_html.py` - 界面组装器 * CSS3特效设计 * JavaScript交互特效 * 🌟 结语 📖 引言 中秋节,这个承载着千年文化的传统节日,以其独特的满月寓意着团圆与和谐。我们不妨用Python这门优雅的编程语言,来创造一个富有诗意的中秋节月相可视化器。本文将带您通过代码的艺术,重现天空中月亮的盈亏变化,并在中秋节这个特殊的日子里,为我们的程序增添一抹传统文化的色彩。 🎯 项目概述 我们将构建一个功能丰富的月相可视

By Ne0inhk