STL--list

news2024/9/30 23:36:28

一、list介绍

列表是序列容器,允许在序列内的任何位置执行恒定时间插入和擦除操作,以及双向迭代

列表容器作为双向链表实现;双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个和后一个元素

它们与forward_list非常相似:主要区别在于forward_list对象是单链表,因此它们只能向前迭代,从而更简单高效

与其他基本标准序列容器(array、vector和 deque)相比,list在任意位置进行插入、移除元素的执行效率更高

与其他序列容器相比,list和 forward_lists 的主要缺点是不支持任意位置的随机访问。例如,要访问列表中的第六个元素,必须从已知位置(如开始或结束)迭代到该位置,这需要这些元素之间的距离的线性时间。它们还会消耗一些额外的内存来保持与每个元素关联的链接信息(这也许是影响存储小数据的大list的因素)

二、list接口

详情可见

list - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/list/list/

1.常见构造

函数名称功能说明
list (size_type n, const value_type& val = value_type())构造的list中包含n个值为val的元素
list()构造空的list
list (const list& x拷贝构造函数
list (InputIterator first, InputIterator last)用[first, last)区间中的元素构造list

2.容量操作

函数名称接口说明
empty

检测list是否为空,是返回true,否则返回false

size返回list中有效节点的个数

3.访问与遍历

函数名称接口说明
begin+end返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器
rbegin+rend返回第一个元素的reverse_iterator,即end位置。返回最后一个元素下一个位置的reverse_iterator,即begin位置
front返回list的第一个节点中值的引用
back返回list的最后一个节点中值的引用

begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动

rbegin与rend为反向迭代器,对迭代器执行++操作,迭代器向前移动

4.修改操作

函数名称接口说明
push_front在list首元素钱插入值为val的元素
pop_front删除list中的第一个元素
push_back在list尾部插入值为val的元素
pop_back删除list最后一个元素
insert在list position位置中插入值为val的元素
erase删除list position位置的元素
swap交换两个list中的元素
clear清空list中的有效元素

5.list迭代器失效

三、list模拟实现

迭代器实现

		iterator begin() { return iterator(_head->_next); }//匿名构造迭代器对象
		iterator begin()const { return iterator(_head->_next); }

返回值返回一个匿名对象构造的迭代器对象

为什么const还可以构造普通迭代器?

因为const修饰*this,也就是一个指针,指针本身不可以改变,但是可以对齐指针指向的内容修改。也就是_head本身不可以改变,但是_head指向的next可以改变

对于常量迭代器对象,可以采用重新实现普通迭代的方式,但是这种方式过于繁琐,并且与普通迭代器的事项方式基本相同,因此采用类模板多个参数的处理方式

//常量迭代器类
	template<class T>
	struct __list_const_iterator
	{
		typedef list_node<T> node;
		typedef __list_const_iterator<T> self;//类对象本身
		node* _node;

		__list_const_iterator(node* n)//迭代器初始化
			:_node(n)
		{}

		const T& operator* ()//不能修改数据
		{
			return _node->_data;
		}

		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& li)
		{
			return _node != li._node;
		}
		bool operator==(const self& li)
		{
			return _node == li._node;
		}
	};

自定义类型处理

list中除了可以存储内置类型之外,还可以存放自定义类型数据,因此还需要对list的迭代器做自定义类型内容的处理

	struct test_A
	{
		int _a1;
		int _a2;
		test_A(int a1=0, int a2=0)
			:_a1(a1), _a2(a2)
		{}
	};

	void test_2()
	{
		list<test_A> lt;//指定内部为自定义类型
		lt.push_back(test_A(1, 1));
		lt.push_back(test_A(2, 2));
		lt.push_back(test_A(2, 2));

		list<test_A>::iterator it = lt.begin();
		while (it != lt.end())
		{
			cout << *it << " ";
			it++;
		}
		cout << endl;
	}

对于上图这样的一个简单自定义类型,如果仍然使用原来的迭代器输出方式,会产生报错

可将其改为

cout << (*it)._a1 << " ";

但是显然这样的输出方式并不符合一般的书写模式,一般情况下访问指针对象的成员并不会先解引用再读取成员。而是直接使用->的方式,因此需要重载->操作符

		T* operator->()//->运算符重载
		{
			return &_node->data
		}

//此时的调用为
    cout<<it->_a1<<" ";
//相当于it.operator->()->_a1,也就是(test_A*) ->_a1
//但是为了可读性编译器会自动省略一个箭头

insert操作

与vector不同,list的insert操作传入的是迭代器,并且不会出现迭代器失效的位置,因为迭代器的相对位置并没有改变,指向也不改变

#pragma once
#include<iostream>
#include<assert.h>
using std::cout;
using std::endl;
namespace my_list
{
	//节点类
	template<class T>
	struct list_node//默认访问权限是public,不对成员的访问限制
	{
		list_node<T>* _next;
		list_node<T>* _prev;
		T _data;

		list_node(const T& x=T())//匿名对象做缺省值,T需要默认构造
			:_next(nullptr), _data(x), _prev(nullptr)
		{
		}
	};

	//迭代器是原生指针或者是自定义类型
	//普通迭代器类
	template<class T,class Ref,class Ptr>
	//Ref与Ptr是为了适用常量迭代器,Ref=T&	Ptr=T*
	struct __list_iterator
	{
		typedef list_node<T> node;
		typedef __list_iterator<T,Ref,Ptr> self;//类对象本身
		node* _node;

		__list_iterator(node* n)//迭代器初始化
			:_node(n)
		{}

		Ref operator* ()
		//常量迭代器与普通迭代器只有返回值不同
		{
			return _node->_data;
		}
		Ptr operator->()
		{
			return &_node->_data;
		}

		self& operator++()//返回迭代器类对象
		{
			_node = _node->_next;
			return *this;
		}
		self& operator++(int)//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& li)
		{
			return _node != li._node;
		}
		bool operator==(const self& li)
		{
			return _node == li._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_const_iterator<T> const_iterator;//常量迭代器
		void empty_init()
		{
			_head = new node;
			_head->_next = _head;
			_head->_prev = _head;
		}
		list()
		{
			empty_init();
		}
		template<class Iterator>
		list(Iterator first, Iterator last)
		{
			empty_init();//空初始化
			while (first != last)
			{
				push_back(*first);
				first++;
			}
		}
		void swap(list<T>& tmp)//套用std库中的swap方便实现拷贝
		{
			std::swap(_head, tmp._head);
		}
		list(const list<T>& cst)//拷贝构造
		{
			empty_init();
			list<T> tmp(cst.begin(), cst.end());
			swap(tmp);
		}
		list<T>& operator=(list<T> lt)//赋值构造
		//如果引用传参会导致拷贝
		{
			swap(lt);
			return *this;
		}
		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}



		//迭代器
		iterator begin() { return iterator(_head->_next); }//匿名构造迭代器对象
		const_iterator begin()const { return const_iterator(_head->_next); }
		iterator end() { return iterator(_head); }
		const_iterator end()const { return const_iterator(_head); }



		//增删查改
		void push_back(const T& x)
		{
			node* tail = _head->_prev;
			node* newnode = new node(x);
			tail->_next = newnode;
			newnode->_prev = tail;
			newnode->_next = _head;
			_head->_prev = newnode;
			newnode->_data = x;
		}
		//void push_back(const T& x)
		//{
		//	insert(end(), x);
		//}
		void push_front(const T& x)
		{
			insert(begin(), x);
		}
		void pop_back()
		{
			erase(--end());
		}
		void insert(iterator pos,const T& x)
		{
			node* cur = pos._node;
			node* prev = cur->_prev;

			node* new_node = new node();

			prev->_next = new_node;
			new_node->_prev = prev;
			new_node->_next = cur;
			cur->_prev = new_node;
			new_node->_data = x;
		}

		iterator erase(iterator pos)
		{
			assert(pos != end());
			node* prev = pos._node->_prev;
			node* next = pos._node->_next;

			prev->_next = next;
			next->_prev = prev;
			delete pos._node;

			return iterator(next);
		}
		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				it=erase(it);
			}
		}
	private:
		node* _head;//哨兵位,不含数据
	};




	template<typename T>
	void show(const list<T>& ls)
	{
		//auto it = ls.begin();
		//while (it != ls.end())
		//{
		//	cout << *it << " ";
		//	++it;
		//}
		//cout << endl;
		for (auto ch : ls)
		{
			cout << ch << " ";
		}
		cout << endl;
	}


	void test_1()
	{
		list<int> l1;
		l1.push_back(1);
		l1.push_back(2);
		l1.push_back(3);
		l1.push_back(4);
		show(l1);

		const list<int> lt1;
		//const对象在定义的时候是不具有const属性的,否则无法进行初始化

		list<int> l2;
		l2 = l1;
		show(l2);

		list<int> l3 = l1;
		show(l3);
	}



	struct test_A
	{
		int _a1;
		int _a2;
		test_A(int a1=0, int a2=0)
			:_a1(a1), _a2(a2)
		{}
	};


	void test_2()
	{
		list<test_A> lt;//指定内部为自定义类型
		lt.push_back(test_A(1, 1));
		lt.push_back(test_A(2, 2));
		lt.push_back(test_A(3, 3));

		list<test_A>::iterator it = lt.begin();
		while (it != lt.end())
		{
			//cout << (*it)._a1 << " ";
			cout << it->_a1 << " " << it->_a2 <<endl;
			it++;
		}
		cout << endl;
	}

	void test_3()
	{
		list<test_A> lt;
		lt.push_back(test_A(1, 1));
		lt.push_back(test_A(2, 2));
		lt.push_back(test_A(3, 3));

		lt.insert(lt.begin(), test_A(5,5));
		list<test_A>::iterator it_2 = lt.begin();
		while (it_2 != lt.end())
		{
			//cout << (*it)._a1 << " ";
			cout << it_2->_a1 << " " << it_2->_a2 << endl;
			it_2++;
		}
	}
}

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

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

相关文章

3.rabbitMQ之发布确认高级和整合springboot(重要)找了很多博客整理出来的

1.极端情况下 rabbitMQ需要重启,导致消息投递失败(生产者发消息全部丢失)(交换机或者队列出问题) 生产者需要把数据放到缓存,用定时任务重新发送 解决方法: 0.必须配置文件写 spring.rabbitmq.publisher-confirm-typecorrelatedspring.rabbitmq.publisher-returnstruecorrelati…

appuploader 入门使用

回想一下我们发布 iOS 应用&#xff0c;不仅步骤繁琐&#xff0c;非常耗时。一旦其中一步失误了&#xff0c;又得重新来。作为一名优秀的工程师不应该让这些重复的工作在浪费我们的人生。在软件工程里面&#xff0c;我们一直都推崇把重复、流程化的工作交给程序完成。这次的文章…

【shell脚本】for循环语句

循环语句与函数 一、循环与遍历1.1循环1.2遍历1.3循环与遍历 二、for循环2.1for循环的基本格式2.2for循环小实验2.3双层for循环实验 三、while循环3.1 while格式 四、跳出循环4.1continue跳出循环实验4.2break跳出循环实验 一、循环与遍历 1.1循环 循环 (Loop) 是计算机编程中…

不会前端,怎么快速打造属于自己的个人博客?

个人博客 简介提前准备 一、初始化vuepress项目二、页面配置首页配置顶部配置顶部导航栏路由配置侧边导航栏配置 三、打包部署四、数据统计插槽自定义插槽配置整体结构页面效果 项目地址 简介 主要教大家如何快速搞一个属于自己的博客网站&#xff0c;特别是一些不怎么会前端的…

【C++】——类与对象(上)

文章目录 1. 前言2. 面向过程和面向对象3. 类的引入4. 类的定义4.1 类的俩种定义方式 5. 类的访问限定符及封装5.1 类的访问限定符5.2 封装 6. 类的作用域7. 类的实例化8. 类对象的存储方式9. this指针9.1 this指针特性 10. 结尾 1. 前言 今天我们来学习C初期最重要的知识点&a…

用于无线传感器网络路由的改进leach协议(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 当前&#xff0c;无线传感器由于技术的发展得到更加广泛的应用&#xff0c;针对无线传感器网络&#xff08;WSN&#xff09;的…

linux重装mmsegmentation

前言 换了个电脑&#xff0c;就想着把之前的mmsegmentation-V0.26.0代码放到新环境&#xff0c;结果踩了不少坑~ 过程 官方步骤 0 安装miniconda 1 创建conda 环境 最开始用的是python3.10&#xff0c;后来发现版本太高不是一件好事&#xff0c;所以装的python3.8 2 安装…

FineBI 6.0入门基础(二)

在图形中分析 组件还可以进行复制,如下图 复制后,切换为【自定义图表】 1.将【毛利额】调整为折线(在图形属性里面进行调整) 2.由于【毛利额】和【毛利额环比增长率】数值差距较大,可将指标中的【毛利额环比增长率】调整为右值轴 3.将图例调整显示位置(组件样式-图例…

ZooKeeper 避坑指南: ZooKeeper 3.6.4 版本 BUG 导致的数据不一致问题

作者&#xff1a;子葵 背景 ZooKeeper 作为分布式系统的元数据中心&#xff0c;对外服务的数据一致性需要得到很好的保证&#xff0c;但是一些老版本的 ZooKeeper 在一些情况下可能无法保证数据的一致性&#xff0c;导致依赖 ZooKeeper 的系统出现异常。 某用户使用 3.4.6 版…

回归问题(AI笔记)

人工智能 回归问题 1943 年&#xff0c;心理学家沃伦麦卡洛克 (Warren McCulloch)和数理逻辑学家沃尔特皮茨(Walter Pitts)通过对生物神经元的研究&#xff0c; 提出了模拟生物神经元机制的人工神经网络的数学模型 &#xff0c;这一成果被美国神经学家弗 兰克罗森布拉特(Frank …

(别再手动点APP了)UiAutomator2自动化测试框架带你玩转APP操作

目录 前言 一、uiautomator/uiautomator2的前生今世 1.官方文档介绍 2.梳理一下脉络 3.三款框架对比 二、uiautomator2简介 1.项目组成 2.工作原理 三、环境搭建 1.安装uiautomator2 2.初始化设备 3.init时都干了啥&#xff1f; 四、基础操作 1.连接设备 2.命令…

手把手教你搭建 Webpack 5 + React 项目

前言 在平时工作中&#xff0c;为减少开发成本&#xff0c;一般都会使用脚手架来进行开发&#xff0c;比如 create-react-app。脚手架都会帮我们配置好了 webpack&#xff0c;但如果想自己搭建 webpack 项目要怎么做呢&#xff1f;这边文章将介绍如何使用 webpack 5 来搭建 re…

HNU-操作系统OS-实验Lab2

OS_Lab2_Experimental report 湖南大学信息科学与工程学院 计科 210X wolf &#xff08;学号 202108010XXX&#xff09; 前言 实验一过后大家做出来了一个可以启动的系统&#xff0c;实验二主要涉及操作系统的物理内存管理。操作系统为了使用内存&#xff0c;还需高效地管理…

C++全栈知识体系 2.0

C 全栈知识体系 一个记录C知识的学习网站&#xff01; 包含内容: C(基础、函数、知识点、IO框架、新特性), 算法, 数据库(MySQL、ElasticSearch、Redis), 编程四大件, 架构, 微服务, 中间件(ZeroMQ、Dubbo、Consul、Logstash、Kong), 工具, 部署(Docker、k8s、Istio), 项目(开源…

YOLOv7环境配置的一些细节

评论区和私信问我问题的同学们不要急&#xff0c;你们的问题我一直在研究&#xff0c;只是还没成功(>﹏<)&#xff0c;如果完成了我会第一时间发出来并通知你的(≧∇≦)/ 本文将讲解YOLOv7环境配置的一些细节&#xff08;YOLOv5环境配置也适用&#xff0c;之前在配gpu版本…

【移动端网页布局】流式布局案例 ⑦ ( 水平排列的图片链接 2 | 浮动设置 | 盒子模型类型设置 | 结构伪类选择器 )

文章目录 一、水平排列的图片链接样式及核心要点1、实现效果2、HTML 结构3、CSS 样式 二、完整代码示例1、HTML 标签结构2、CSS 样式3、展示效果 一、水平排列的图片链接样式及核心要点 1、实现效果 实现如下样式 , 水平排列的图片链接 , 第一个图片占宽度的 50% , 第二第三个 …

【视频解读】Window上安装和使用autogluon V0.7

1.使用conda安装的python环境 教程使用的是极简版miniconda,由于我们的电脑中安装了anaconda&#xff0c;所以不需要进行进一步安装。python版本为3.9&#xff0c;博客里面有anaconda和python版本的对应关系。注意查看版本autogluon V0.4需要3.8或者3.9和3.10&#xff0c;pip版…

分类预测 | MATLAB实现基于PSO-NN、SVM、KNN、DT的多特征数据分类预测,二分类及多分类

分类预测 | MATLAB实现基于PSO-NN、SVM、KNN、DT的多特征数据分类预测&#xff0c;二分类及多分类 目录 分类预测 | MATLAB实现基于PSO-NN、SVM、KNN、DT的多特征数据分类预测&#xff0c;二分类及多分类分类效果基本描述程序设计参考资料 分类效果 基本描述 Matlab实现基于PSO…

智能家居项目

文章目录 一、功能描述二、整体框架结构及编译2.1、整体框架2.2、编译Makefile 三、工厂模式四、守护进程udev五、监控视频储存六、遇到的问题和未解决的问题七、代码流程图7.1、树莓派&#xff08;8线程 &#xff0c;2进程&#xff09;7.2、手机APP 八、内网穿透&#xff08;实…

机器学习(五):基于KNN模型对高炉发电量进行回归预测分析

文章目录 专栏导读1、KNN简介2、KNN回归模型介绍3、KNN模型应用-高炉发电量预测3.1数据集信息:3.2属性信息3.3数据准备3.4数据标准化和划分数据集3.5寻找最佳K值3.6建立KNN模型预测4、完整代码专栏导读 ✍ 作者简介:i阿极,CSDN Python领域新星创作者,专注于分享python领域知…