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

最新电子电气架构(EEA)调研-3

而新一代的强实时性、高确定性,以及满足CAP定理的同步分布式协同技术(SDCT),可以实现替代TSN、DDS的应用,且此技术已经在无人车辆得到验证,同时其低成本学习曲线、无复杂二次开发工作,将开发人员的劳动强度、学习曲线极大降低,使开发人员更多的去完成算法、执行器功能完善。 五、各大车厂的EEA 我们调研策略是从公开信息中获得各大车厂的EEA信息,并在如下中进行展示。 我们集中了华为、特斯拉、大众、蔚来、小鹏、理想、东风(岚图)等有代表领先性的车辆电子电气架构厂商。        1、华为 图12 华为的CCA电子电气架构              (1)华为“计算+通信”CC架构的三个平台                         1)MDC智能驾驶平台;                         2)CDC智能座舱平台                         3)VDC整车控制平台。        联接指的是华为智能网联解决方案,解决车内、车外网络高速连接问题,云服务则是基于云计算提供的服务,如在线车主服务、娱乐和OTA等。 华

By Ne0inhk
Apache IoTDB 架构特性与 Prometheus+Grafana 监控体系部署实践

Apache IoTDB 架构特性与 Prometheus+Grafana 监控体系部署实践

Apache IoTDB 架构特性与 Prometheus+Grafana 监控体系部署实践 文章目录 * Apache IoTDB 架构特性与 Prometheus+Grafana 监控体系部署实践 * Apache IoTDB 核心特性与价值 * Apache IoTDB 监控面板完整部署方案 * 安装步骤 * 步骤一:IoTDB开启监控指标采集 * 步骤二:安装、配置Prometheus * 步骤三:安装grafana并配置数据源 * 步骤四:导入IoTDB Grafana看板 * TimechoDB(基于 Apache IoTDB)增强特性 * 总结与应用场景建议 Apache IoTDB 核心特性与价值 Apache IoTDB 专为物联网场景打造的高性能轻量级时序数据库,以 “设备 - 测点” 原生数据模型贴合物理设备与传感器关系,通过高压缩算法、百万级并发写入能力和毫秒级查询响应优化海量时序数据存储成本与处理效率,同时支持边缘轻量部署、

By Ne0inhk
SQL Server 2019安装教程(超详细图文)

SQL Server 2019安装教程(超详细图文)

SQL Server 介绍) SQL Server 是由 微软(Microsoft) 开发的一款 关系型数据库管理系统(RDBMS),支持结构化查询语言(SQL)进行数据存储、管理和分析。自1989年首次发布以来,SQL Server 已成为企业级数据管理的核心解决方案,广泛应用于金融、电商、ERP、CRM 等业务系统。它提供高可用性、安全性、事务处理(ACID)和商业智能(BI)支持,并支持 Windows 和 Linux 跨平台部署。 一、获取 SQL Server 2019 安装包 1. 官方下载方式 前往微软官网注册账号后,即可下载 SQL Server Developer 版本(

By Ne0inhk