C++——list的特性及使用

ops/2024/9/25 10:29:48/

list的特性        

STL中的list是指带头双向循环列表list每个元素的存储相互独立,因为其节点存储位置独立不连续,其插入和删除不需要挪动其他元素效率比起vector更高。但也因为存储空间不连续的问题,不能做到和vector一样的随机访问。

 list的模拟实现

template<class T>struct ListNode{ListNode(const T& val = T()):_pPre(nullptr),_pNext(nullptr),_val(val){}ListNode<T>* _pPre;ListNode<T>* _pNext;T _val;};//List的迭代器类template<class T, class Ref, class Ptr>class ListIterator{typedef ListNode<T>* PNode;typedef ListIterator<T, Ref, Ptr> Self;public:ListIterator(PNode pNode = nullptr):_pNode(pNode){}ListIterator(const Self& l){_pNode = l.getpNode();}//T& operator*();Ref operator*(){return _pNode->_val;}//T* operator->();Ptr operator->(){return &_pNode->_val;}Self& operator++(){_pNode = _pNode->_pNext;return *this;}Self operator++(int){Self tmp(*this);_pNode = _pNode->_pNext;return tmp;}Self& operator--(){_pNode = _pNode->_pPre;return *this;}Self& operator--(int){Self tmp(*this);_pNode = _pNode->_pPre;return tmp;}bool operator!=(const Self& l){return _pNode != l.getpNode();}bool operator==(const Self& l){return _pNode == l.getpNode();}PNode getpNode()const{return _pNode;}private:PNode _pNode;};//list类template<class T>class list{typedef ListNode<T> Node;typedef Node* PNode;public:typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T&> const_iterator;public:///// List的构造list(){CreateHead();}list(int n, const T& value = T()){_size += n;CreateHead();PNode cur = _pHead;while (n--){PNode newnode = new Node(value);cur->_pNext = newnode;newnode->_pPre = cur;newnode->_pNext = _pHead;_pHead->_pPre = newnode;cur = cur->_pNext;}}template <class Iterator>list(Iterator first, Iterator last){Iterator cur = first;while (cur != last){push_back(cur.getpNode()->_val);cur++;}}list(const list<T>& l){CreateHead();for (auto& a : l){push_back(a);}}list<T>& operator=(const list<T> l){list<T> tmp(l);swap(tmp);}~list(){clear();delete _pHead;_pHead = nullptr;}///// List Iteratoriterator begin(){return _pHead->_pNext;}iterator end(){return _pHead;}const_iterator begin()const{return _pHead->_pNext;}const_iterator end()const{return _pHead;}///// List Capacitysize_t size()const{return _size;}bool empty()const{return _size == 0;}// List AccessT& front(){return _pHead->_pNext->_val;}const T& front()const{return _pHead->_pNext->_val;}T& back(){return _pHead->_pPre->_val;}const T& back()const{return _pHead->_pPre->_val;}// List Modifyvoid push_back(const T& val) { insert(end(), val); }void pop_back() { erase(--end()); }void push_front(const T& val) { insert(begin(), val); }void pop_front() { erase(begin()); }// 在pos位置前插入值为val的节点iterator insert(iterator pos, const T& val){PNode newnode = new Node(val);PNode cur = pos.getpNode();PNode prev = cur->_pPre;newnode->_pNext = cur;cur->_pPre = newnode;prev->_pNext = newnode;newnode->_pPre = prev;_size++;return iterator(newnode);}// 删除pos位置的节点,返回该节点的下一个位置iterator erase(iterator pos){PNode cur = pos.getpNode();PNode prev = cur->_pPre;PNode next = cur->_pNext;prev->_pNext = next;next->_pPre = prev;delete cur;_size--;return iterator(next);}void clear(){iterator it = begin();while (it != end()){it = erase(it);}}void swap(list<T>& l){std::swap(_pHead, l.getpHead());std::swap(_size, l.size());}PNode getpHead()const{return _pHead;}private:void CreateHead(){_pHead = new Node;_pHead->_pNext = _pHead;_pHead->_pPre = _pHead;_size = 0;}PNode _pHead;size_t _size;};

迭代器失效问题

与vector不同,list插入时迭代器不会失效,因为节点相互独立的原因,所以list的插入不会改变其节点存储位置,如此一来迭代器的指向也不会有影响。

 

不过删除时仍会出现迭代器失效,迭代器指向的节点被删除时该迭代器失效(指向的节点失效,迭代器自然也就失效了),其余不受影响。

 

 list与vector的区别

vectorlist
插入与删除插入与删除都可能需要挪动部分元素,时间复杂度为O(n),插入还往往伴随着扩容,又因为其需要连续的存储空间还可能出现开辟新空间,拷贝数据,释放旧空间的操作,整体效率低下。插入与删除的时间复杂度均为O(1),存储空间的独立使其不需要扩容,需要新节点时才进行申请,并且不需要挪动数据。
随机访问存储空间连续,支持随机访问,查找的时间复杂度为O(1)不支持随机访问,查找的时间复杂度为O(n)
迭代器使用原生指针使用被封装的原生指针
空间利用率因其内存连续,不易造成内存碎片,空间利用率高,但缓存利用率高因其节点是动态开辟而来,且相互独立。容易造成内存碎片,空间利用率低,但缓存利用率低

总结:如果需要高效存储、需要随机访问且不关心插入删除效率则使用vector。反之需要大量插入删除查找,不关心随机访问则使用list


http://www.ppmy.cn/ops/34438.html

相关文章

opencv基础篇 ——(十五)多边形与凸边型

概念 在计算机视觉和图像处理中&#xff0c;多边形和凸多边形是常用的几何形状描述方式。它们在描述对象的形状、边界或区域时非常有用。下面我将简要介绍它们的概念和特点&#xff1a; 多边形&#xff08;Polygon&#xff09;定义&#xff1a; 多边形是一个平面内的闭合图形&…

spring注解之——@Service

Spring框架中的注解Service用于将类标记为Spring应用程序上下文中的服务组件。它主要用于指示带注释的类充当应用程序中的服务层组件。 以下是关于注释的一些要点Service&#xff1a; 业务逻辑&#xff1a;通常&#xff0c;带有注释的类Service包含业务逻辑。这些类负责封装和…

string容器

目录 string函数的构造 string赋值操作 string字符串拼接 string字符串查找和替换 string字符串比较 string字符存取 string插入与删除 string字串 string函数的构造 #include<iostream> #include<cstring> using namespace std; void test01() {string s…

《自动机理论、语言和计算导论》阅读笔记:p215-p351

《自动机理论、语言和计算导论》学习第 11 天&#xff0c;p215-p351总结&#xff0c;总计 37 页。 一、技术总结 1.constrained problem 2.Fermat’s lats theorem Fermat’s Last Theorem states that no three positive integers a, b and c satisfy the equation a^n b…

SpringApplicationBuilder启动类

SpringApplicationBuilder 原文链接&#xff1a;http://t.csdnimg.cn/B6L6u

python 学习: 矩阵运算

摘要: 本贴通过例子描述 python 的矩阵运算. 1. 一般乘法 (mm 与 matmul) 代码: input_mat1 torch.tensor([[1, 2, 3, 4],[1, 2, 2, 3]])input_mat2 torch.tensor([[1, 2, 3, 3],[2, 1, 2, 3],[3, 1, 2, 2],[2, 3, 2, 3]])print("input_mat1: ", input_mat1)prin…

C# 用户控件UserControl事件解绑资源释放

用户控件继承子 UserControl 。 现在有个业务需求在UserControl 所在的窗体关闭时解除事件HMouseDown绑定。 因没有相关的Close事件。后来本人想了一个办法在 ROICtlDesigner类的 Dispose 方法中执行相关的释放代码 比如解除事件绑定 释放资源 public partial class ROICt…

CMake使用

一、CMake 是什么 CMake 是一个跨平台的自动化构建系统&#xff0c;它使用配置文件 CMakeLists.txt 来管理软件构建过程。CMake 基于 Makefile 做了二次开发。 二、单个文件目录 # CMake 最低版本号要求 cmake_minimum_required(VERSION 3.16.3)# 工程名 project(CMakeSingle)…