【STL容器】list

news2024/11/26 1:24:39

文章目录

  • 一、list定义
  • 二、list的迭代器
  • 三、list的元素操作
  • 四,list的优缺点


一、list定义

list本质是一个双向带头循环链表

在这里插入图片描述

template<class T>
struct list_node
{
	list_node* prev;
	T val;
	list_node* next;
};

template<class T>
class list
{
	typedef list_node<T> node; 
private:
	node* head;
};

二、list的迭代器

不同于vector的迭代器,list的迭代器是一个类,原因是list是链式空间,普通指针的++,–不能访问到正确的地址,因此需要运算符重载++,–等。

template<class T, class ref, class ptr>
struct list_iterator
{
private:
	typedef list_node<T> node;
	typedef list_iterator<T, ref, ptr> self;
public:
	node* _cur;
};

这里有一个重点,模板参数ref,ptr是干什么的?
在list类中是这样定义iterator
typedef list_iterator<T, T&, T*> iterator;
typedef list_iterator<T, const T&, const T*> const_iterator;
这表示 ref传的是T的引用,ptr传的是T的指针,这不是多此一举吗?
但偏偏list的源码也是这样的。
在这里插入图片描述
这是为什么呢?
我们将list_iterator封装为一个类,主要是想重载它的++,–等运算符,以便正确使用iterator;
下面这是list_literator的前置++,它的返回值应该是 list_iterator<T>&,但如果我使用的是const_iterator,它的返回值应该是const list_iterator<T>&,二者的区别仅仅只是返回值不同,但仅仅返回值不同,不能构成函数重载。这样仅仅想靠一个类list_iterator是不行的,那就只能再写一个类const_list_iterator.

返回值 operator++()
{
	_cur = _cur->next;
	return *this;
}

但如果传参时,T& | const T& 作为一个参数传递,就可以只写list_iterator,来完成iterator 和 const_iterator.虽然本质上还是创建了2个类,但创建的工作由编译器解决,我们只用手写一个类就够了。

template<class T, class ref, class ptr>
	struct list_iterator
	{
	private:
		typedef list_node<T> node;
		typedef list_iterator<T, ref, ptr> self;
		//iterator 则 ref = T&
		//const_iterator 则 ref = const T&
	public:
		//成员变量
		node* _cur = nullptr;
		//迭代器:构造,++, *
		list_iterator(node* it = nullptr)
		{
			_cur = it;
		}
		self& operator++()    
		{
			_cur = _cur->_next;
			return *this;
		}
		self& operator++(int)
		{
			self tmp(*this);
			_cur = _cur->_next;
			return tmp;
		}
		ref operator*() const
		{
			return _cur->_val;
		}
	};

ptr同理,它主要服务operator->()

ptr operator->() const
{
	return &(_cur->_val);
}

注:这里有个小知识,operator的返回值可能让人感到疑惑。

在这里插入图片描述
C++ 中的 operator-> 被用于重载类的成员访问操作符 ->。这个操作符通常用于访问类的成员函数和成员变量,而且在许多情况下,它应该返回一个指向类的成员的指针。这是因为 -> 操作符通常用于访问类的成员,而类的成员可以是函数或变量。


三、list的元素操作

list的插入删除,本质就是双向带头链表的插入删除,下面给出一些简单的模拟实现。

list(const T& t = T())
{
	head = new node;
	node* tmp = new node;
	tmp->_val = t;
	tmp->_next = head;
	tmp->_prev = head;
	head->_next = tmp;
	head->_prev = tmp;
	++_size;
}
list(const list<T>& t)
{
	for (auto& e : t)
	{
		push_back(e);
	}
}
~list()
{
	iterator it = begin();
	while (it != end())
	{
		it = erase(it);
	}
	delete head;
	head = nullptr;
}
void swap(list<T>& lt)
{
	std::swap(head, lt.head);
	std::swap(size, lt.head);
}
list<T>& operator=(list<T> lt)
{
	swap(lt);
}
//iterator
iterator begin()
{
	return iterator(head->_next);
}
iterator end()
{
	return iterator(head);
}
//capacity
size_t size()
{
	return _size;
}
//modify
void push_back(const T& t = T())
{
	insert(end(), t);
}
void push_front(const T& t = T())
{
	insert(begin(), t);
}
void insert(iterator pos, const T& t)
{
	node* cur = pos._cur;
	node* prev = cur->_prev;
	node* tmp = new node;
	tmp->_val = t;
	tmp->_prev = prev;
	tmp->_next = cur;
	prev->_next = tmp;
	cur->_prev = tmp;
	++_size;
}
void pop_back()
{
	iterator it(head->_prev);
	erase(it);
}
void pop_front()
{
	erase(begin());
}
iterator erase(iterator pos)
{
	node* cur = pos._cur;
	node* prev = cur->_prev;
	node* next = cur->_next;
	prev->_next = next;
	next->_prev = prev;
	delete cur;
	--_size;
	return iterator(next);
}

list在使用时,一定要注意迭代器失效的问题。

四,list的优缺点

STL(标准模板库)中的 std::list 是一个双向链表(doubly linked list)的实现,它具有一些优点和缺点,适用于不同的使用情况。

优点:

  1. 插入和删除效率高: std::list 对于插入和删除操作非常高效,因为在双向链表中,插入和删除元素只需要改变相邻节点的指针,而不需要移动其他元素。

  2. 稳定的迭代器: 在插入和删除元素时,std::list 保持了迭代器的有效性。这意味着在遍历列表时进行插入或删除操作不会导致迭代器失效,这在其他容器中(如 std::vector)是不成立的。

  3. 内存管理灵活: 由于链表的节点可以分散存储在内存中,std::list 具有一定的内存分配灵活性。这可以避免动态数组(如 std::vector)可能会发生的重新分配和复制开销。

缺点:

  1. 随机访问效率低: std::list 不支持常数时间的随机访问,因为要遍历链表需要 O(n) 的时间复杂度。如果需要频繁的随机访问元素,std::vector 更适合。

  2. 性能较差的缓存局部性: 由于链表节点在内存中是离散分布的,因此对于大型数据集,std::list 的性能可能受到缓存局部性的影响,而数组式容器更有可能利用好缓存。

  3. 不支持随机访问和下标访问: std::list 不支持像数组那样的随机访问或下标访问,这限制了其在某些应用中的使用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1022335.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis性能压测、监控工具及优化方案

Redis是一款高性能的开源缓存数据库&#xff0c;但是在实际应用中&#xff0c;我们需要对Redis进行性能压测、监控以及优化&#xff0c;以确保其稳定性和高可用性。本文将介绍Redis性能压测、监控工具及优化方案。 01 Redis性能压测 常用的Redis性能压测工具有&#xff1a; …

探秘移动端BI:发展历程与应用前景解析

什么是移动端BI 维基百科 上对于 移动端商业智能的定义是这样的 > Mobile BI is a system that presents historical and real-time information on mobile devices for effective decision-making and management support. It enables analysis on smartphones and table…

DLT645-2007智能电表通讯规约 协议读取数据实战

【本文发布于https://blog.csdn.net/Stack_/article/details/132946097&#xff0c;未经许可不得转载&#xff0c;转载须注明出处】 协议文档&#xff1a;DL-T 645-2007 多功能电能表通信协议 先用电表厂家提供的上位机进行通讯并拦截数据&#xff0c;再对照协议文档进行以下分…

springcloud3 分布式事务解决方案seata之AT模式5

一 seata的AT模式 1.1 AT模式与XA模式 XA模式一阶段不提交事务&#xff0c;锁定资源&#xff1b;AT模式一阶段直接提交&#xff0c;不锁定资源。 XA模式依赖数据库机制实现回滚&#xff1b;AT模式利用数据快照实现数据回滚。 XA模式强一致&#xff1b;AT模式最终一致 1.2 …

python虚拟环境(venv)

一、什么是python环境 首先要知道什么是python环境&#xff1f; Python环境主要包括以下内容&#xff1a; 解释器 python.exe (python interpreter&#xff0c;使用的哪个解释看环境配置) Lib目录 标准库 第三方库&#xff1a;site-pakages目录&#xff0c;默认安装第三方…

【内网穿透】公网远程访问本地硬盘文件

公网远程访问本地硬盘文件【内网穿透】 文章目录 公网远程访问本地硬盘文件【内网穿透】前言1. 下载cpolar和Everything软件3. 设定http服务器端口4. 进入cpolar的设置5. 生成公网连到本地内网穿透数据隧道 总结 前言 随着云概念的流行&#xff0c;不少企业采用云存储技术来保…

Vue.js入门模板语法及Vue.js实现购物车---详细讲解

前言 前面我们学习了Vue的基础入门&#xff0c;接下来我们学习有关Vue的模板语法&#xff0c;学习Vue语法能提高我们的前端开发效率 Vue.js 使用了基于 HTML 的模板语法&#xff0c;允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。所有 Vue.js 的模板都是合法的 HTML &a…

hive、spark、presto 中的增强聚合-grouping sets、rollup、cube

目录 1、什么是增强聚合和多维分析函数&#xff1f; 2、grouping sets - 指定维度组合 3、with rollup - 上卷维度组合 4、with cube - 全维度组合 5、Grouping__ID、grouping() 的使用场景 6、使用 增强聚合 会不会对查询性能有提升呢&#xff1f; 7、对grouping sets、…

2023年中国航空装备行业研究报告

第一章 行业概况 1.1 定义和分类 航空装备行业是现代工业的重要组成部分&#xff0c;涵盖了飞机、航空发动机以及航空设备与系统三大核心领域。这些领域不仅在技术上高度复杂&#xff0c;而且在国家经济、社会发展和国家安全方面都具有至关重要的作用。 首先&#xff0c;飞机…

​ 生产者消费者问题(条件变量 互斥锁)

本篇文章对生产者消费者&#xff08;模型&#xff09;问题进行了详解。其中给出了基于阻塞队列的生产者消费者模型demo代码和对涉及到的条件变量与互斥锁的操作也进行了详细解释。解释了条件变量等待时&#xff0c;为什么还需要一把锁的问题。对生产者消费者&#xff08;模型&a…

六、展示信息添加 animation 动态效果

简介 给每个信息组件内容添加动画效果,通过 animation 来怎么增强用户浏览时的交互体验。欢迎访问个人的简历网站预览效果 本章涉及修改与新增的文件:App.vue、main.ts、first.vue 、second.vue、third.vue 、fourth.vue 、fifth.vue 一、安装 animae 插件 先安装 animate…

【ELK】日志系统部署

一、ELK日志分析系统 1、ELK的组成 ElasticSearchLogStashKibana ELK基于这三个开源日志的收集、存储、检索和可视化的解决方案&#xff1b;可帮助用户快速定位和分析应用程序的故障&#xff0c;监控应用程序性能和安全&#xff0c;以及提供丰富的数据分析和展示功能。 2、完…

Word 自动编号从10 以后编号后面的空白很大

目录 1、打开Word&#xff0c;选中需要修改的行。 2、点击鼠标右键&#xff0c;选择调整列表缩进一项&#xff0c;弹出对话框。 3、弹出对话窗口里将编号之后里面的选项&#xff0c;改成不特别标注。 4、点击确定&#xff0c;可以看到效果。 多余的缩进已经没有了。至此&…

从零开始搭建java web springboot Eclipse MyBatis jsp mysql开发环境

文章目录 1 第一步软件安装1.1 下载并安装Eclipse1.2 下载并安装Java1.3 下载并安装Apache Maven1.4 下载并安装MySQL 2 创建所需要的表和数据3 创建Maven 工程、修改jdk4 通过pom.xml获取所需要的jar包5 安装Eclipse的MyBatis插件6 创建文件夹以及jsp文件7 创建下面各种java类…

没有炫光的台灯有哪些?无眩光灯具推荐

很多家长有时候会说孩子觉得家里的台灯灯光刺眼&#xff0c;看书看久了就不舒服。这不仅要看光线亮度是否柔和&#xff0c;还要考虑台灯是不是有做遮光式设计。没有遮光式设计的台灯&#xff0c;光源外露&#xff0c;灯光会直射孩子头部&#xff0c;孩子视线较低&#xff0c;很…

掌握Katalon Studio 导入 swagger 接口文档,接口测试效率提升100%

katalon studio大家都已经不陌生了&#xff0c;是一款现在非常主流的自动化测试工具&#xff0c;包括了web、api、APP&#xff0c;甚至PC应用程序都可以使用它来完成自动化测试。 swagger是一款RESTFUL接口的文档在线自动生成软件&#xff0c;swagger是一个规范和完整的框架&a…

Python 基于人脸识别的实验室智能门禁系统的设计,附可视化界面

1 简介 本基于人脸识别的实验室智能门禁系统通过大数据和信息化的技术实现了门禁管理流程的信息化的管理操作。平台的前台页面通过简洁的平台页面设计和功能结构的分区更好的提高用户的使用体验&#xff0c;没有过多的多余的功能&#xff0c;把所有的功能操作都整合在功能操作…

物理内存分配

目录 内核物理内存分配接口 内存分配行为&#xff08;物理上&#xff09; 内存分配的行为操作 内存 三个水位线 水线计算 水位线影响内存分配行为 内存分配核心__alloc_pages 释放页 1、内核物理内存分配接口 struct page *alloc_pages(gfp_t gfp, unsigned int ord…

【go语言基础】go类型断言 type switch + case,t := x.(type)

有这么一个场景&#xff0c;当你在和用户对接的时候&#xff0c;调取第三方接口&#xff0c;但是第三方接口的时常变化的&#xff0c;比如从string类型变为int&#xff0c;这个时候你需要再去判断类型&#xff0c;获取第三方接口的参数。比较麻烦。 针对这一场景&#xff0c;g…

爬虫工具篇-ProxyBroker-代理IP管理

前言 随着互联网的不断发展&#xff0c;大量的信息和数据都被存储在各种不同的网站上。为了获取这些信息和数据&#xff0c;我们经常需要使用爬虫工具来自动化地从网站上抓取数据。然而&#xff0c;在一些情况下&#xff0c;网站可能会采取一些反爬虫措施&#xff0c;例如向IP…