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

list列表

 list 容器的优点

  •         高效的插入和删除:由于std::list是基于带头双向循环链表实现的,插入和删除操作复杂度O(1)
  •         稳定的迭代器:相对于vector这种,list迭代器失效的情况比较少
  •         动态内存管理:std::list可以动态调整大小,根据需要分配和释放内存。能够有效地处理大量元素

但因为是链表结构,空间不连续,占用了更多的内存。在list 的迭代器当中也就没有实现 operator+ 这个函数。

定义私有成员:

	private:Node* _head;size_t _size;

在官方的List源代码当中,List容器的结点定义在一个结构体当中。

链表节点
	template<class T>                 //模板声明struct list_node{list_node<T>* _next;          //成员变量list_node<T>* _prev;T _val;list_node(const T& val = T()) //构造函数:_next(nullptr), _prev(nullptr), _val(val){}};

使用 struct而不是 class,意味着所有成员默认是 public的。

定义正向迭代器

通过模板参数来同时实现 普通迭代器 和 const 迭代器,避免代码冗余。

	// T: 数据类型, Ref: 引用类型(T&/const T&), Ptr: 指针类型(T*/const T*)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->_val;}Ptr operator->()                 // 成员访问(编译器会优化掉一个->){return &_node->_val;}//前置++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& it) const{return _node != it._node;}bool operator==(const self& it) const{return _node == it._node;}
};

举例使用

定义反向迭代器
  1. 核心思想​​:rbegin()对应 end()(即最后一个元素的下一个),rend()对应 begin()

  2. ​​操作​​:对反向迭代执行 ++操作,实际是调用其内部封装的正向迭代器的 --操作。

	template<class T, class Ref, class Ptr>struct __list_reverse_iterator{typedef list_node<T> Node;typedef __list_reverse_iterator<T, Ref, Ptr> self;Node* _node;__list_reverse_iterator(Node* node):_node(node){}Ref operator*(){return _node->_val;}Ptr operator->(){return &_node->_val;}// 注意:反向迭代器的++是正向的--self& operator++(){_node = _node->_prev;return *this;}self operator++(int){self tmp(*this);_node = _node->_prev;return tmp;}// 反向迭代器的--是正向的++self& operator--(){_node = _node->_next;return *this;}self operator--(int){self tmp(*this);_node = _node->_next;return tmp;}bool operator!=(const self& it) const{return _node != it._node;}bool operator==(const self& it) const{return _node == it._node;}};
定义一个list类

对之前

  • list_node结构体 重命名为 Node
  • 正向迭代器重命名为 iterator 和 const_iterator
  • 反向迭代器重命名为 reverse_iterator 和 const_reverse_iterator
	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;//反向迭代器typedef __list_reverse_iterator<T, T&, T*> reverse_iterator;typedef __list_reverse_iterator<T, const T&, const T*> const_reverse_iterator;......};

构造函数

		void empty_init()       //创建一个空指针{_head = new Node;_head->_prev = _head;_head->_next = _head;_size = 0;}list()                //构造函数   {empty_init();}

析构函数

		~list()          {clear();                //析构函数delete _head;_head = nullptr;}void clear()                //清理{iterator it = begin();while (it != end()){it = erase(it);}_size = 0;}

拷贝构造函数

		// lt2(lt1)list(const list<T>& lt)//list(const list& lt){empty_init();for (auto& e : lt){push_back(e);}}

push_back

		void push_back(const T& x){insert(end(), x);}

push_front

		void push_front(const T& x){insert(begin(), x);}

pop_back

		void pop_back(){erase(--end());}

pop_front

		void pop_front(){erase(begin());}

insert

		iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);prev->_next = newnode;newnode->_next = cur;cur->_prev = newnode;newnode->_prev = prev;++_size;return newnode;}

要返回新插入的元素的位置,防止外部迭代器失效。 

erase

		iterator erase(iterator pos){assert(pos != end());Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;--_size;return next;}

size()

		size_t size()	{ return _size;	}

empty

		bool empty() const { return _size == 0; }

front()

		T& front(){assert(_size > 0);return _head->_next->_val;}

back()

		T& back(){assert(_size > 0);return _head->_prev->_val;}

赋值运算符重载函数和swap()函数

		void swap(list<T>& lt)    {std::swap(_head, lt._head);std::swap(_size, lt._size);}list<T>& operator=(list<T> lt)//list& operator=(list lt){swap(lt);return *this;}

其实上述的 赋值重载运算符函数当中的模板类的类型名可以不用 List<T>,我们知道List<T>是类型名,List是类名,对于模版类,类型名不是 List,而是List<T>,但是如果是在类模板当中写,可以写类名也可以写类型名(下述写法也可以):

list& operator=(list lt)

总代码
#pragma once
#include<assert.h>
#include <iostream>using namespace std;namespace bit
{template<class T>struct list_node      //底层是结构体 {list_node<T>* _next;list_node<T>* _prev;T _val;list_node(const T& val = T()):_next(nullptr), _prev(nullptr), _val(val){}};// typedef __list_iterator<T, T&, T*> iterator;// typedef __list_iterator<T, const T&, const T*> const_iterator;// T: 数据类型, Ref: 引用类型(T&/const T&), Ptr: 指针类型(T*/const T*)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->_val;}Ptr operator->() // 成员访问(编译器会优化掉一个->){return &_node->_val;}//前置++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& it) const{return _node != it._node;}bool operator==(const self& it) const{return _node == it._node;}};// 反向迭代器template<class T, class Ref, class Ptr>struct __list_reverse_iterator{typedef list_node<T> Node;typedef __list_reverse_iterator<T, Ref, Ptr> self;Node* _node;__list_reverse_iterator(Node* node):_node(node){}Ref operator*(){return _node->_val;}Ptr operator->(){return &_node->_val;}// 注意:反向迭代器的++是正向的--self& operator++(){_node = _node->_prev;return *this;}self operator++(int){self tmp(*this);_node = _node->_prev;return tmp;}// 反向迭代器的--是正向的++self& operator--(){_node = _node->_next;return *this;}self operator--(int){self tmp(*this);_node = _node->_next;return tmp;}bool operator!=(const self& it) const{return _node != it._node;}bool operator==(const self& it) const{return _node == it._node;}};/*template<class T>struct __list_const_iterator{typedef list_node<T> Node;Node* _node;__list_const_iterator(Node* node):_node(node){}const T& operator*(){return _node->_val;}__list_const_iterator<T>& operator++(){_node = _node->_next;return *this;}__list_const_iterator<T> operator++(int){__list_const_iterator<T> tmp(*this);_node = _node->_next;return tmp;}bool operator!=(const __list_const_iterator<T>& it){return _node != it._node;}bool operator==(const __list_const_iterator<T>& it){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;//反向迭代器typedef __list_reverse_iterator<T, T&, T*> reverse_iterator;typedef __list_reverse_iterator<T, const T&, const T*> const_reverse_iterator;// 这么设计太冗余了,看看库里面如何设计的//typedef __list_const_iterator<T> const_iterator;// 这样设计const迭代器是不行的,因为const迭代器期望指向内容不能修改// 这样设计是迭代器本身不能修改// typedef const __list_iterator<T> const_iterator;// const T* ptr1;// T* const ptr2;// 如何设计const迭代器?iterator begin(){//return _head->_next;return iterator(_head->_next);}iterator end(){return _head;//return iterator(_head);}const_iterator begin() const{//return _head->_next;return const_iterator(_head->_next);}const_iterator end() const{return _head;//return const_iterator(_head);}// 反向迭代器的起始是最后一个元素reverse_iterator rbegin(){return reverse_iterator(_head->_prev);}// 反向迭代器的结束是头节点(第一个元素的前一个位置)reverse_iterator rend(){return reverse_iterator(_head);}const_reverse_iterator rbegin() const{return const_reverse_iterator(_head->_prev);}const_reverse_iterator rend() const{return const_reverse_iterator(_head);}void empty_init()         //ok{_head = new Node;_head->_prev = _head;_head->_next = _head;_size = 0;}list()                  //构造函数{empty_init();}// lt2(lt1)list(const list<T>& lt)   //拷贝构造函数//list(const list& lt){empty_init();for (auto& e : lt){push_back(e);}}void swap(list<T>& lt)      //swap{std::swap(_head, lt._head);std::swap(_size, lt._size);}list<T>& operator=(list<T> lt)    //赋值运算符重载//list& operator=(list lt){swap(lt);return *this;}~list()          //析构函数{clear();delete _head;_head = nullptr;}void clear()      // ok{iterator it = begin();while (it != end()){it = erase(it);}_size = 0;}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());}// pos位置之前插入iterator insert(iterator pos, const T& x) //insert{Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);prev->_next = newnode;newnode->_next = cur;cur->_prev = newnode;newnode->_prev = prev;++_size;return newnode;}iterator erase(iterator pos)  //erase{assert(pos != end());Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;--_size;return next;}size_t size()          //ok      {/*size_t sz = 0;iterator it = begin();while (it != end()){++sz;++it;}return sz;*/return _size;}bool empty() const { return _size == 0; }T& front(){assert(_size > 0);return _head->_next->_val;}T& back(){assert(_size > 0);return _head->_prev->_val;}private:Node* _head;size_t _size;};

list与vector的区别
vector        list
底 层 结 构动态顺序表,是一段连续空间带头结点的双向循环链表
随 机 访 问支持随机访问,访问某个元素效率O(1)不支持随机访问,访问某个元素
效率O(N)
插 入 和 删 除任意位置插入和删除效率低,需要搬移元素,时间复杂
度为O(N),插入时有可能需要增容,增容:开辟新空
间,拷贝元素,释放旧空间,导致效率更低
任意位置插入和删除效率高,不
需要搬移元素,时间复杂度为
O(1)
空 间 利 用 率底层为连续空间,不容易造成内存碎片,空间利用率
高,缓存利用率高
底层节点动态开辟,小节点容易
造成内存碎片,空间利用率低,
缓存利用率低
迭 代 器原生态指针对原生态指针(节点指针)进行封装
迭 代 器 失 效失效情况相对较多失效情况相对较少
使 用 场 景需要随机访问,不关心插入删除大量插入和删除操作,不关心随
机访问

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

相关文章:

  • 团购网站做摄影网站编程开发
  • Kurt-Blender零基础教程:第4章:粒子篇
  • Qt常用控件之QTextEdit
  • ImageHash - Python 图像哈希库
  • 初识 Vue
  • 做网站销售水果上海建设安全协会网站
  • 正能量视频素材免费下载网站现代营销手段有哪些
  • Prj11-8088单板机C语言大综合(一)
  • 44.网络层
  • 肇庆网站制作软件郑州企业网络推广公司
  • ALLaM - 专为阿拉伯语设计的AI大语言模型
  • Docker Compose 停止命令对比
  • 北京网站推广优化更改wordpress端口
  • 优势的seo网站优化排名网站内容质量
  • Transformer 能做什么?—— 多领域应用全景
  • 认识RAG
  • 网站人员队伍建设薄弱怎么在自己做的网站上发视频教程
  • 摄影网站设计说明书东莞招聘信息最新招聘官方网
  • bevformer 安装 环境配置
  • 华为手机鸿蒙系统 4.2 / 4.3 安装谷歌框架的详细教程
  • 南昌网站开发爱网站长尾
  • 工业摄像头是应用于工业现场的高性能数字图像采集设备
  • 【08】VisionMaster入门到精通——卡尺工具和边缘查找
  • RRateLimiter的使用
  • 做网站html整合资源加强全市网站建设
  • 使用opencv来识别信用卡的号码
  • 【rabbitmq 高级特性】全面详解RabbitMQ重试机制
  • 在飞腾D2000/8平台下ubuntu内核添加WX1860和WX1820的驱动
  • docker相关进程的作用
  • 建设的网站如何让用户注册宁波发布最新通报