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

【C++】STL·List

1. list的介绍及使用

1.1list介绍

List文档介绍

1.2 list的使用

list中的接口比较多,此处类似,只需要掌握如何正确的使用,然后再去深入研究背后的原理,已 达到可扩展的能力。以下为list中一些常见的重要接口。

1.2.1 list的构造

list<int>lt1(5);           构造空的list
list<int>lt2(3, 2);        构造的list中包含n个值为val的元素
list<int>lt3(lt2);         拷贝构造函数
int arr[] = { 1,2,3,4,5 };
list<int>lt4(arr, arr + 5);用[first, last)区间中的元素构造list

1.2.2 list iterator的使用

	lt1.begin();  返回第一个元素的迭代器  lt1.end();    返回最后一个元素下一个位置的迭代器lt1.rbegin(); 返回第一个元素的reverse_iterator, 即end位置lt1.rend();   返回最后一个元素下一个位置的reverse_iterator, 即begin位置

1.2.3 list capacity

	lt1.size();  返回list中有效节点的个数lt1.empty(); 检测list是否为空,是返回true,否则返回false
1.2.4 list element access

	lt1.front(); 返回list的第一个节点中值的引用lt1.back();  返回list的最后一个节点中值的引用
1.2.5 list modifiers

	lt1.push_back(1);			尾插lt1.push_front(1);			头插lt1.pop_back();				尾删lt1.pop_front();			头删lt1.insert(lt1.begin(), 1); 在list position 位置中插入值为val的元素lt1.erase(lt1.begin());		删除list position位置的元素lt1.swap(lt2);				交换两个list中的元素lt1.clear();				清空list中的有效元素
1.2.6 list的迭代器失效

迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。

void TestListIterator1()
{int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };list<int> l(array, array + sizeof(array) / sizeof(array[0]));auto it = l.begin();while (it != l.end()){// erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给其赋值l.erase(it);++it;}
}
// 改正
void TestListIterator()
{int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };list<int> l(array, array + sizeof(array) / sizeof(array[0]));auto it = l.begin();while (it != l.end()){l.erase(it++);//it = l.erase(it);}
}

2. list的模拟实现

2.1 模拟实现list

#pragma once
#include<iostream>
#include<vector>
using namespace std;
namespace XiaoHai
{template<class T>struct list_node{T _data;list_node<T>* _next;list_node<T>* _prev;list_node(const T& x = T()):_data(x), _next(nullptr), _prev(nullptr){ }};template<class T, class ref, class Ptr>struct Reverse_iterator{Iterator _it;typedef Reverse_iterator<Iterator, Ref, Ptr> Self;Reverse_iterator(Iterator it):_it(it){}Ref operator*(){iterator tmp(_it);--tmp;return *tmp;}Ptr operator->(){return &(operator*());}self operator++(int){self tmp(_it);--_it;return *tmp;}self operator--(int){self tmp(_it);++_it;return *tmp;}self operator++(){--_it;return *tmp;}self operator--(){++_it;return *tmp;}bool operator!=(const Self& s){return _it != s._it;}};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;}T* operator->(){return &_node->_data;}self& operator++(){_node = _node->_next;return *this;}self& operator++(int){__list_iterator<T>tmp(*this);_node = _node->_next;return tmp;}self& operator--(){_node = _node->_prev;return *this;}self& operator--(int){__list_iterator<T>tmp(*this);_node = _node->_prev;return tmp;}bool operator!=(const __list_iterator<T>& it)const{return _node != it._node;}bool operator ==(const __list_iterator<T>& it)const{return !(_node != it._node);}};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 iterator(_head->_next);}iterator end(){return iterator(_head);}const_iterator begin() const{return iterator(_head->_next);}const_iterator end() const{return iterator(_head);}void empty_init(){_head = new Node;_head->_next = _head;_head->_prev = _head;}list(){empty_init();}//lt2(lt1)list(const list<T>&lt){empty_init();for (const auto& e:lt){push_back(e);}}list(initializer_list<int>il){empty_init();for (const auto& e : il){push_back(e);}}void swap(list<T>&lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}//lt1 = lt2list<T>& operator=(const list<T>* lt){swap(lt);return *this;}/*list<T>& operator=(const list<T>* lt){if (this != &lt){clear();for (const auto& e : il){push_back(e);}}return *this;}*/~list(){clear();delete _head;_head = nullptr;}void clear(){iterator it = begin();while (it != end()){it = erase(it);}}void push_back(const T& x){insert(end(), x);}void push_front(const T& x){insert(begin(), x);}void pop_back(){erase(--end());}void pop_front(){erase(begin());}void insert(iterator pos, const T& val){Node* cur = pos._node;Node* newnode = new Node(val);Node* prev = cur->_prev;//prev newnode curprev->_next = newnode;newnode->_next = cur;cur->_prev = newnode;newnode->_prev = prev;++_size;}iterator& erase(iterator pos){Node* cur = pos._node;Node* next = cur->_next;Node* prev = cur->_prev;//prev (cur) nextprev->_next = next;next->_prev = prev;delete cur;--_size;return iterator(next);}size_t size(){return _size;}private:Node* _head;size_t _size = 0;};
}

2.2 list的反向迭代器

通过前面例子知道,反向迭代器的++就是正向迭代器的--,反向迭代器的--就是正向迭代器的++, 因此反向迭代器的实现可以借助正向迭代器,即:反向迭代器内部可以包含一个正向迭代器,对正向迭代器的接口进行包装即可。

	template<class T, class ref, class Ptr>struct Reverse_iterator{Iterator _it;typedef Reverse_iterator<Iterator, Ref, Ptr> Self;Reverse_iterator(Iterator it):_it(it){}Ref operator*(){iterator tmp(_it);--tmp;return *tmp;}Ptr operator->(){return &(operator*());}self operator++(int){self tmp(_it);--_it;return *tmp;}self operator--(int){self tmp(_it);++_it;return *tmp;}self operator++(){--_it;return *tmp;}self operator--(){++_it;return *tmp;}bool operator!=(const Self& s){return _it != s._it;}};

3. list与vector的对比

vector与list都是STL中非常重要的序列式容器,由于两个容器的底层结构不同,导致其特性以及 应用场景不同

vectorlist
底层结构动态顺序表,一段连续空间带头结点的双向循环链表
随机访问支持随机访问,访问某个元素效率O(1)不支持随机访问,访问某个元素效率O(n)
插入和删除尾插效率高,任意位置插入和删除效率低,需要搬移元素,时间复杂度为O(N),插入时有可能需要增容,增容: 开辟新空间,拷贝元素,释放旧空间,导致效率更低任意位置插入和删除效率高, 不需要搬移元素,时间复杂度 为O(1)
空间利用率底层为连续空间,不容易造成内存碎片,空间利用率高,缓存利用率高底层节点动态开辟,小节点容易造成内存碎片,空间利用率 低,缓存利用率低
迭代器原生态指针对原生态指针(节点指针)进行封装
迭代器失效插入操作如果导致底层空间重新开辟,则迭代器就会失效,删除操作不光会导致指向被删除元素的迭代器失效,删除元素后面的迭代器也会失效插入元素不会导致迭代器失效,删除元素时,只会导致当前迭代器失效,其他迭代器不受影响
使用场景需要高效存储,支持随机访问,不关心插入删除效率大量插入和删除操作,不关心随机访问


文章转载自:

http://s0UxWCIo.kjgdm.cn
http://oUAEoTxp.kjgdm.cn
http://O0R3qXRz.kjgdm.cn
http://BdC8sdDZ.kjgdm.cn
http://lG5uM3IQ.kjgdm.cn
http://aFcFsYov.kjgdm.cn
http://6P8pS8vH.kjgdm.cn
http://w6w3NB0M.kjgdm.cn
http://VcqOOOBc.kjgdm.cn
http://79PLS5Q4.kjgdm.cn
http://m7KEuplh.kjgdm.cn
http://6kVF17oZ.kjgdm.cn
http://RhUf7IlS.kjgdm.cn
http://D3LcF7Vo.kjgdm.cn
http://4qksjNWx.kjgdm.cn
http://GUZGr7xU.kjgdm.cn
http://KQEqx55z.kjgdm.cn
http://rC2ftaS6.kjgdm.cn
http://lc9bkXCL.kjgdm.cn
http://rkfOt6ft.kjgdm.cn
http://1HayLgBT.kjgdm.cn
http://MgMaoRno.kjgdm.cn
http://tLcWUPyL.kjgdm.cn
http://qpU2xZtk.kjgdm.cn
http://5saqgFw6.kjgdm.cn
http://Xev4K3kT.kjgdm.cn
http://bsHH5Mbl.kjgdm.cn
http://7RhiyzUB.kjgdm.cn
http://33BUeroL.kjgdm.cn
http://V9lFWjKm.kjgdm.cn
http://www.dtcms.com/a/382043.html

相关文章:

  • 网络安全与iptables防火墙配置
  • Django + Vue3 前后端分离技术实现自动化测试平台从零到有系列 <第一章> 之 注册登录实现
  • Flink面试题及详细答案100道(41-60)- 状态管理与容错
  • 从基础到高级:一文快速认识MySQL UPDATE 语句
  • 基于KAZE算法的织物图像拼接matlab仿真,对比SIFT和SURF
  • 知识输出零散没有体系怎么办
  • 【LeetCode】37. 解数独
  • Redis常见性能问题
  • 数据帮助我们理解未知世界
  • 泛型通配符 T、E、K、V、?
  • STL简介及string
  • Ditty WordPress插件displayItems端点未授权访问漏洞(CVE-2025-8085)
  • 【性能优化需要关注的参数——Batches】
  • React Device Detect 完全指南:构建响应式跨设备应用的最佳实践
  • 开始 ComfyUI 的 AI 绘图之旅-Qwen-Image(十一)
  • python根据路径获取文件后缀名
  • c++雾里探花-静态多态
  • Java基础知识(十五)
  • 2025.9.14英语红宝书
  • Easy系列PLC枚举变量类型(为什么可以不实例化直接使用)
  • python全栈-自动化office
  • smartctl_exporter smartctl 统计信息
  • 软件测试常见Bug清单
  • 大数据电商流量分析项目实战:可视化 数据分析(九)
  • Kafka核心概念深入浅出:消费者组(Consumer Group)机制全解析
  • ZYNQ PS读写PL BRAM
  • [数据结构] 队列 (Queue)
  • Git : 基本操作
  • Vue模板中传递对象或数组时,避免直接使用字面量[]和{}
  • 26考研——内存管理_虚拟内存管理(3)