C++ STL : 模拟实现STL中的list类
文章目录
- list
- list的介绍
- list的优缺点
- list的迭代器失效问题
- 实现的接口
- 节点部分
- 迭代器部分
- list部分
- 代码实现
list
list的介绍
list的文档介绍
- list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
- list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向 其前一个元素和后一个元素。
- list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高 效。
- 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率 更好。
- 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list 的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间
开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这 可能是一个重要的因素)
其实list就是数据结构中的双向循环链表, 实现思路我之前有写过
带头双向循环链表
STL中的list和双向链表大体的思路一样,只是多了迭代器和模板等c++的特性,所以下面大部分代码我都直接复用了以前过的代码
list的优缺点
优点:
1.list的存储方式不像vector是线性的连续的,它是链式的存储空间,只保持了逻辑上的连续,所以不需要考虑扩容的问题,更加有效的利用空间
2.因为是链式的存储方式,所以不需要像vector一样插入删除时需要挪动数据,所以插入删除时的时间复杂度为O(1)
缺点:
1.因为是链式结构,所以不支持下标的随机访问,导致很多算法用起来十分麻烦
list的迭代器失效问题
list的迭代器失效问题主要就体现在erase上,因为list的空间并不是连续的,而是通过prev和next两个指针来找到前后的结点,而一旦erase掉一个结点,此时再对那个节点使用++或者–就会导致迭代器失效的报错问题,因为节点已经被释放,自然就无法通过自身的prev和next访问到前后的结点。
实现的接口
节点部分
迭代器部分
list的迭代器不再像之前的一样直接用指针来模拟,而是封装了一个指向节点类的指针,所以我们还需要重载迭代器的运算符,来保证它能够像指针一样使用
__list_node<T>* _next;
__list_node<T>* _prev;
T _data;
__list_node(const T& data = T());
typedef __list_node<T> Node;
typedef __list_iterator<T, Ref, Ptr> Self;
Node* _node;
__list_iterator(Node* node);
Ref operator*();
Ptr operator->();
Self& operator++();
Self operator++(int);
Self& operator--();
Self operator--(int);
bool operator==(const Self& it);
bool operator!=(const Self& it);
list部分
默认成员函数部分
list() : _head(new Node);
list(const list<T>& l) : _head(new Node);
list<T>& operator=(list<T> l);
~list();
迭代器部分
typedef __list_node<T> Node;
typedef __list_iterator<T, T&, T*> iterator;
typedef __list_iterator<T, const T&, const T*> const_iterator;
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
容量部分
size_t size() const;
bool empty()const;
元素访问部分
T& front();
const T& front()const;
T& back();
const T& back()const;
修改部分
void clear();
void pop_front();
void push_front(const T& val);
void pop_back() ;
void push_back(const T& val);
iterator erase(iterator pos);
iterator insert(iterator pos, const T& val);
void swap(list<T>& l);
私有成员
Node* _head; //头结点
代码实现
#pragma once
#include<cassert>namespace lee
{//节点template<class T>struct __list_node{__list_node<T>* _next;__list_node<T>* _prev;T _data;__list_node(const T& data = T()): _data(data), _next(nullptr), _prev(nullptr){}};//迭代器//使用三个模板参数来实现代码复用,可以根据传的参数来同时实现const_iterator和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;}/*这里其实使用了多个->,例如有一个对象it,it->_data就等价于it.operator->()->_data。这里重载的部分就返回了指向对象的指针,(*it的类型)->_data,然后再通过那个指针访问数据。如果存在嵌套的类,这里则会一直递归调用对象中重载的->,直到取到数据,但是这里因为编译器优化 所以只需要写一次就行*/Ptr operator->(){return &_node->_data;}Self& operator++(){_node = _node->_next;return *this;}Self operator++(int){Self temp(*this);++(*this);return temp;}Self& operator--(){_node = _node->_prev;return *this;}Self operator--(int){Self temp(*this);--(*this);return temp;}bool operator==(const Self& it){return _node == it._node;}bool operator!=(const Self& it){return _node != it._node;}};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;/*------------------------------------------------------------默认成员函数部分Member functions------------------------------------------------------------*/list() : _head(new Node){_head->_next = _head;_head->_prev = _head;}list(const list<T>& l) : _head(new Node){_head->_next = _head;_head->_prev = _head;for (auto it : l){push_back(it);}}list<T>& operator=(list<T> l){swap(l);return *this;}~list(){clear();delete _head;_head = nullptr;}/*------------------------------------------------------------迭代器部分Iterators:------------------------------------------------------------*/iterator begin(){return iterator(_head->_next);}iterator end(){return iterator(_head);}const_iterator begin() const{return const_iterator(_head->_next);}const_iterator end() const {return const_iterator(_head);}/*------------------------------------------------------------修改部分Modifiers:------------------------------------------------------------*/void swap(list<T>& l){std::swap(_head, l._head);}iterator insert(iterator pos, const T& val){assert(pos._node != nullptr);Node* cur = pos._node;Node* prev = cur->_prev;Node* newNode = new Node(val);prev->_next = newNode;cur->_prev = newNode;newNode->_next = cur;newNode->_prev = prev;return iterator(newNode);}iterator erase(iterator pos){ assert(_head->_next != _head);Node* cur = pos._node;Node* next = cur->_next;next->_prev = cur->_prev;cur->_prev->_next = next;delete cur;return iterator(next);}//和数据结构里面实现的一样,可以直接复用insert和erasevoid push_back(const T& val){insert(end(), val);//head}void pop_back() { erase(--end()); //head->prev}void push_front(const T& val){insert(begin(), val);//head->next;}void pop_front(){erase(begin());//head->next;}void clear(){auto it = begin();while (it != end()){it = erase(it);}}/*------------------------------------------------------------元素访问部分Element access:------------------------------------------------------------*/T& front(){return _head->_next->_data;}const T& front()const{return _head->_next->_data;}T& back(){return _head->_prev->_data;}const T& back()const{return _head->_prev->_data;}/*------------------------------------------------------------容量部分Capacity------------------------------------------------------------*/size_t size()const{size_t count = 0;auto it = begin();while (it != end()){count++;it++;}return count;}bool empty()const{return _head->_next == _head;}private:Node* _head;};
}
C++ STL : 模拟实现STL中的list类相关推荐
- C++ STL : 模拟实现STL中的关联式容器unordered_map/unordered_set
目录 unordered_map/unordered_set unordered_map/unordered_set与map/set的区别 底层哈希桶的改造 仿函数 Key值的获取方法 hash(ke ...
- C++ STL : 模拟实现STL中的容器适配器stack和queue
目录 什么是容器适配器 stack stack的文档介绍-(来自cplusplus) stack的实现 queue queue的文档介绍-(来自cplusplus) queue的实现 什么是容器适配器 ...
- C++ STL : 模拟实现STL中的vector类
文章目录 vector vector的介绍 vector的优缺点 实现时需要注意的细节问题 1. Capacity增长问题 2. memset等函数来带的按字节拷贝问题 3. 深浅拷贝问题 4. 迭代 ...
- C++ STL : 模拟实现STL中的关联式容器map和set
目录 关联式容器 键值对 底层红黑树的改造 仿函数 红黑树的迭代器 完整代码 set set的文档介绍 set的实现 map map的文档介绍 map的实现 operator[] 完整代码 multi ...
- C++ STL : 模拟实现STL中的容器适配器priority_queue
目录 priority_queue 文档介绍 实现思路 思路 仿函数 实现 priority_queue 文档介绍 文档介绍 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含 ...
- C++ STL : 模拟实现STL中的string类
string的文档介绍 string是表示字符序列的类 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作 单字节字符字符串的设计特性. string类是使用c ...
- 【C++】vector的模拟实现@STL —— 迭代器失效问题
vector的模拟实现@STL 1. (constructor) & (destructor) 2. 一系列基本接口 2.1 size & capacity 2.2 [] 2.3 it ...
- 1/22 测试一(STL 模拟 贪心)C.(贪心,给出气球,输出最好成绩)Contest Balloons
1/22 测试一(STL 模拟 贪心) C.(贪心,给出气球,输出最好成绩)Contest Balloons One tradition of ACM-ICPC contests is that a ...
- c++ 的 stl模板库_C ++中的标准模板库(STL)
c++ 的 stl模板库 Standard Template Library (STL) is a collection of standard C++ template classes. It co ...
最新文章
- PNAS:张航课题组揭示人类为何“扭曲”概率信息
- 单片机模块学习之数码管
- python编程少儿游戏编程_少儿编程课堂|python – 用游戏学编程
- BOOST_MP11_VERSION宏用法的测试程序
- 加密算法—MD5、RSA、DES
- CentOS下Redis 2.2.14安装配置详解
- 9.29 csp-s模拟测试55 联+赛+题
- 使用web进行数据库管理
- 微软云存储更换品牌 免费空间将翻番达到15GB
- 如何在表格里做计算机统计表,如何运用Excel编制统计表并做一般数据分析?-excel统计怎么做,最简单的统计表格怎么做...
- python编写背单词程序
- java培训机构那个好点
- K2P padavan固件下宽带与IPTV融合
- boost库的安装和使用
- Python PEP8编码规范
- 手机裂脑纪:中国式审美还有救吗?
- cucumber Hooks @Before @After 不执行
- 微软pop3服务器,真算孤陋寡闻。。微软旗下的邮箱都支持POP3收发邮件了
- 《电磁场与电磁波》MATLAB 仿真实验
- 排序算法之冒泡排序代码
热门文章
- 元组-元组变量的常用操作
- SocketIO-nio
- java文件中有中文,在windows下因编码不一致,而导致编译失败的处理方法。
- python文件下载器代码_GitHub - applechi/pythonCollection: python代码集合(文件下载器、pdf合并、极客时间专栏下载、掘金小册下载、新浪微博爬虫等)...
- postman cookie设置_是时候抛弃Postman了,因为REST Client更香
- java B2B2C Springcloud电子商城系统-Spring Cloud常见问题与总结(四)
- org.hibernate.MappingException: entity class not found hbm可以解析,但是实体类不能解析...
- Unknown opcode
- Cisco 2960 交换机密码设置
- 洛谷 - P2770 航空路线问题(最大费用最大流+路径打印)