当前位置: 首页 > news >正文

[C++ STL] list类的刨析及简易实现

目录

引言

1. STL list库函数用法概述

1.1 基本构造与初始化

1.2 元素插入与删除

1.3 遍历操作

2. 自我实现list类

2.1 代码结构概述

2.2 节点结构

2.3 迭代器实现

2.4 list类实现 

3. 总结


引言

在 C++ 标准模板库(STL)中,list是一种常用的容器,它实现了双向链表的数据结构。与vector不同,list在插入和删除元素时具有较好的性能,尤其是在中间位置进行操作。本文将详细剖析list类的库函数用法,并结合提供的代码展示如何自我实现一个简单的list类,重点解析迭代器的实现方法。

1. STL list库函数用法概述

1.1 基本构造与初始化

STL 的list类提供了多种构造函数,以下是一些常见的用法:

#include <iostream>
#include <list>int main() {// 默认构造函数std::list<int> lt1;// 初始化列表构造函数std::list<int> lt2 = {1, 2, 3, 4, 5};// 拷贝构造函数std::list<int> lt3(lt2);return 0;
}

1.2 元素插入与删除

list类提供了丰富的插入和删除元素的方法:


int main() {std::list<int> lt = {1, 2, 3};// 在尾部插入元素lt.push_back(4);// 在头部插入元素lt.push_front(0);// 在指定位置插入元素auto it = std::next(lt.begin(), 2);lt.insert(it, 5);// 删除尾部元素lt.pop_back();// 删除头部元素lt.pop_front();// 删除指定位置元素it = std::next(lt.begin(), 1);lt.erase(it);return 0;
}

1.3 遍历操作

可以使用迭代器或范围for循环来遍历list中的元素:

int main() {std::list<int> lt = {1, 2, 3, 4, 5};// 使用迭代器遍历for (auto it = lt.begin(); it != lt.end(); ++it) {std::cout << *it << " ";}std::cout << std::endl;// 使用范围for循环遍历for (auto& e : lt) {std::cout << e << " ";}std::cout << std::endl;return 0;
}

2. 自我实现list

2.1 代码结构概述

提供的代码实现了一个简单的list类,包含了节点结构、迭代器和list类本身。下面将逐步分析代码的各个部分。

2.2 节点结构

template <class T>
struct list_node 
{T _data;list_node<T>* _prev;list_node<T>* _next;list_node(const T& data = T()): _data(data), _prev(nullptr), _next(nullptr){}
};

list_node是一个模板结构体,用于表示双向链表中的节点。每个节点包含一个数据成员_data,以及指向前一个节点和后一个节点的指针_prev_next

2.3 迭代器实现

迭代器是list类的核心部分,它提供了一种统一的方式来遍历链表中的元素。代码中使用了模板参数来实现普通迭代器和常量迭代器的复用:

template <class T, class Ref, class Ptr> // Ref - &  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--() {_node = _node->_prev;return *this;}Self operator++(int) {Self tmp(*this);_node = _node->_next;return tmp;}Self operator--(int) {Self tmp(*this);_node = _node->_prev;return tmp;}bool operator!=(const Self& s) const {return _node != s._node;}bool operator==(const Self& s) const {return _node == s._node;}
};
  • RefPtr是模板参数,分别表示引用类型和指针类型。通过这种方式,可以在同一个迭代器模板中实现普通迭代器和常量迭代器。
  • operator*()operator->()重载了解引用和箭头运算符,使得迭代器可以像指针一样使用。
  • operator++()operator--()重载了前置递增和递减运算符,用于移动迭代器的位置。
  • operator++(int)operator--(int)重载了后置递增和递减运算符,它们会返回迭代器的旧值,并移动迭代器的位置。
  • operator!=()operator==()重载了不等于和等于运算符,用于比较两个迭代器是否指向同一个节点。

2.4 list类实现 

template <class T>
class list 
{
public:typedef list_node<T> Node;typedef list_iterator<T, T&, T*> iterator;typedef list_iterator<T, const T&, const T*> const_iterator;void empty_init() {_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;}list() {empty_init();}list(initializer_list<T> li) {empty_init();for (auto& e : li) {push_back(e);}}list(const list<T>& lt) {empty_init();for (auto& e : lt) {push_back(e);}}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);}~list(){clear();delete _head;_head = nullptr;}iterator begin() {return _head->_next;}iterator end() {return _head;}const_iterator begin() const {return _head->_next;}const_iterator end() const {return _head;}void push_back(const T& x) {insert(end(), x);}void push_front(const T& x) {insert(begin(), x);}void insert(iterator pos, const T& x) {Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);prev->_next = newnode;cur->_prev = newnode;newnode->_next = cur;newnode->_prev = prev;_size++;}void pop_back() {erase(--end());}void pop_front() {erase(begin());}void erase(iterator pos) {assert(pos != end());Node* next = pos._node->_next;Node* prev = pos._node->_prev;prev->_next = next;next->_prev = prev;delete pos._node;_size--;}size_t size() const {return _size;}bool empty() const {return _size == 0;}void clear() {Node* prev = _head->_next;Node* cur = prev->_next;while (prev != _head) {delete prev;prev = cur;cur = cur->_next;}_size = 0;}private:Node* _head;size_t _size;
};
  • empty_init()函数用于初始化链表的头节点,将其_next_prev指针都指向自身,并将链表的大小初始化为 0。
  • 构造函数提供了默认构造、初始化列表构造和拷贝构造的实现。
  • operator=重载了赋值运算符,使用swap函数实现了高效的赋值操作。
  • begin()end()函数分别返回指向链表第一个元素和最后一个元素之后位置的迭代器。
  • push_back()push_front()函数用于在链表的尾部和头部插入元素,它们都调用了insert()函数。
  • insert()函数在指定位置插入一个新节点,并更新链表的指针和大小。
  • pop_back()pop_front()函数用于删除链表的尾部和头部元素,它们都调用了erase()函数。
  • erase()函数删除指定位置的节点,并更新链表的指针和大小。
  • size()函数返回链表的大小,empty()函数判断链表是否为空。
  • clear()函数用于清空链表中的所有元素,并释放内存。

3. 总结

通过本文的分析,我们深入了解了 C++ STL 库的list类的库函数用法,并结合提供的代码实现了一个简单的list类。重点解析了迭代器的实现方法,通过模板参数的使用,实现了普通迭代器和const迭代器的复用。自我实现list类不仅可以帮助我们更好地理解 STL 容器的底层原理,还可以根据实际需求进行定制和扩展。

 

http://www.dtcms.com/a/272609.html

相关文章:

  • 亚马逊首个“海折节”,缘何加码进口电商?
  • java多线程环境下资源隔离机制ThreadLocal详解
  • C#内插字符串:从语法糖到深度优化
  • 学习笔记(32):matplotlib绘制简单图表-数据分布图
  • 入门级别的Transformer模型介绍
  • Rust中Option和Result详解
  • 微调性能赶不上提示工程怎么办?Can Gradient Descent Simulate Prompting?——论文阅读笔记
  • Apache Shiro 框架详解
  • 【三维生成】FlashDreamer:基于扩散模型的单目图像到3D场景
  • Express 入门指南(超详细教程)
  • 机器学习之逻辑回归和k-means算法(六)
  • 32多串300A保护板测试仪:新能源电池安全的核心守护者
  • 生成式人工智能实战 | 自注意力生成对抗网络(Self-Attention Generative Adversarial Network, SAGAN)
  • 深入理解fork():系统调用创建进程的原理与实践
  • 项目部署:nginx的安装和配置
  • 利用Pandas进行条件替换与向前填充
  • Linux中的命令连接符
  • Layui —— select
  • 图解Java数据容器(三):Queue
  • CAS登录工作流程简述
  • 【前端】【Echarts】ECharts 词云图(WordCloud)教学详解
  • Prompt提示词的主要类型和核心原则
  • 在vscode中和obsidian中使用Mermaid
  • Spring AI Alibaba(2)——通过Graph实现工作流
  • Flutter 与 Android 的互通几种方式
  • Linux 中 sed 命令
  • RedisJSON 路径语法深度解析与实战
  • Spring Boot + Javacv-platform:解锁音视频处理的多元场景
  • 【TCP/IP】12. 文件传输协议
  • MySQL索引操作全指南:创建、查看、优化