List-反向迭代器

news2024/11/18 17:53:25

List

List接口使用

  1. List:双向带头循环的链表,不支持随机访问,排序就是一个大问题
    当大量的插入数据的时候就体现出了优势。

在任意位置以O(1)的时间复杂度插入数据.

  1. 只有一种遍历方式就是迭代器,因为他的物理结构是不连续的无法用下标的方式进行访问
list<int>::iterator it=lt.begin();
while(it!=lt.end())
{
    cout<<*it<<" ";
    ++it;
}
cout<<endl;
  1. lt.sort();自身携带的排序方式,但是效率不太高。

  2. lt.unique();去重数据,先进行排序才能够去除干净。

  3. lt.splice();接合,将链表的节点直接转移到另一个里面去.

#include<iostream>
#include<list>
using namespace std;
int main()
{
	//list<int> l1;
	//l1.push_back(1);
	//l1.push_back(5);
	//l1.push_back(3);
	//l1.push_back(4);
	//l1.push_back(2);
	//l1.push_back(2);
	//l1.push_back(2);
	//l1.push_back(2);
	//l1.sort();
	//l1.unique();//先排序再去重效率更高
	//list<int>::iterator it = l1.begin();
	//while (it != l1.end())
	//{
	//	cout << *it << " ";
	//	++it;
	//}
	//cout << endl;

	list<int> l1;
	list<int> l2;
	for (int i = 1; i <= 4; i++)
	{
		l1.push_back(i);
		l2.push_back(i * 10);
	}

	auto it = l1.begin();
	++it;

	//将l2拼接到l1的指定位置处
	l1.splice(it,l2);
	l1.splice(it,l2,l2.begin(),l2.end());


	//advance 让it指向指定下标位置的数,必须先从头开始
	it = l1.begin();
	advance(it,2);
	//相当于将指定部分长度元素组,头插
	l1.splice(l1.begin(),l1,it,l1.end());

	list<int>::iterator it1 = l1.begin();
	while (it1 != l1.end())
	{
		cout << *it1 << " ";
		++it1;
	}
	cout << endl;

	return 0;
}

list的模拟实现

迭代器

自定义类型进行封装节点指针,自定义类型的运算符重载实现++,和operator*
end()是最后一个数据的下一个位置,就是头结点
迭代器不只是原生指针有可能是。

类型的意义
链表节点的原生指针和一个迭代器对象,他们占用的空间时一样大的,都是4byte,
并且存的值也是一样的。但是对他们使用运算符的意义和结果都是不一样的。

void f()
{
	Node*pnode=_head->next;
	iterator it=_head->next;

	*pnode;
	*it;
}

迭代器的拷贝构造和赋值重载以及析构函数都不需要我们自己实现,默认生成的就行。因为,迭代器是借助节点的指针访问和修改链表。节点属于链表不属于迭代器,所以他不用管释放的过程。默认生成的拷贝就是浅拷贝足以满足拷贝构造和赋值的需求,两个指针指向同一个迭代器同一个位置.

通过自己模拟实现迭代器的功能,使用迭代器去访问和修改链表的相关函数。

const迭代器

普通迭代器可读可写,const迭代器只能读不能修改.就是实现一个const iterator让容器的内容不可修改.这是两个迭代器.

所以要么实现一个不能修改的迭代器一般适应容器是const的,对于const类型和普通类型本身需要声明两个类的迭代器,除了类型名和返回值不同其他都相同,但是为了避免代码的冗余和重复.

可以通过控制模板参数不同的返回值来区别两个类的迭代器。加了一个Ref
这样返回值是const类型就去调用const_iterator的begin和end,普通类型就去调用普通类型的内个。

通过模板参数实现代码的复用,避免了代码的冗余。

如果迭代器指针指向的是一个结构,那我们还是要访问他本身的成员变量。所以要重载一个 operator->
使用场景:日期类。迭代器像Date*指针一样使用,结构体里面用->访问成员变量it->_year;

  • 使用场景(1->2)
void test2()
	{
		list<Date> lt;
		lt.push_back(Date(2022, 1, 1));
		lt.push_back(Date(2022, 2, 2));
		lt.push_back(Date(2022,3,3));
		list<Date>::iterator it = lt.begin();
		while (it != lt.end())
		{
			//1. std::cout << (*it)._year << "." << (*it)._month << "." << (*it)._day << std::endl;
            //2. it->:Date
			std::cout << it->_year<<"."<< it->_month << "."<< it->_day<< std::endl;
			++it;
		}
		std::cout << std::endl;
	}

it.operator->(),返回来是Date*``,Date*访问成员又是一个->所以本来应该是it->->year,这样运算符的可读性变差。编译器进行优化为一个->,所有类型想要重载都会是这样的。

//迭代器中重载这样的函数
T *operator->()
{
	return &_node->_data;
}

如果是const迭代器,所以类似于Ref的添加一个模板参数Ptr.

增删查改

stringvector是连续的物理空间,模拟指针的行为,像指针一样去访问容器,原生指针就是天然的迭代器。支持随机访问,但是增容可能造成浪费空间,插入删除要挪动数据.

list按需申请和释放空间,在任意位置支持O(1)的插入删除。所以vector和list是互补的两个数据结构。

iterator 类去封装节点指针,重载运算符,让他像指针一样。STL的所有容器都不能保证线程安全。
泛型,复用,封装。

insert()

在既定pos的前一个位置进行插入新的节点,list 的迭代器,insert之后不会发生失效。vector会野指针(异地扩容)和意义改变(数据移动覆盖导致)

插入之后,STL里面的会返回插入节点的迭代器指针。

erase()

不能将头结点删除,断言处理.返回删除之后下一个节点.

拷贝构造的实现:深浅拷贝的问题

push_back()的前提是这个链表被初始化了,就需要他已经存在哨兵位的头节点,所以在调用之前要创建一个头结点,并且自己指向自己。

		list(const list<int>& lt)
		{
			_head = new Node();
			_head->_next = _head;
			_head->_prev = _head;
			for (auto e : lt)
			{
				push_back(e);
			}
		}

赋值构造

		list& operator=(const list<int>& lt)
		{
			if (this != &lt)
			{
				clear();
				_head = new Node();
				_head->_next = _head;
				_head->_prev = _head;
				for (auto e : lt)
				{
					push_back(e);
				}
			}
			return *this;
		}
//升级版本		
template<class InputIterator >
		list(InputIterator first, InputIterator last)
		{
			_head = new Node();
			_head->_next = _head;
			_head->_prev = _head;
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		};
		list<T>(const list<T>& lt)
		{
			//避免交换的时候_head为随机值
			_head = new Node();
			_head->_next = _head;
			_head->_prev = _head;

			list<T>tmp(lt.begin(),lt.end());
			std::swap(_head, tmp._head);
		}
		list<T>& operator=(list<T> lt)
		{
			std::swap(_head, lt._head);
			return *this;
		}

非法间接寻址

image-20230202213106258

当迭代器区间初始化list(InputIterator first, InputIterator last)list(size_t n, const T& val = T())同时存在时,

void test4()
{
	list<Date>lt1(5,Date(2022,1,1));//类型不同,走得list()
	list<int>lt2(5,1);//两个都是int,走得迭代器区间那个,造成间接非法寻址
    //匹配函数的时候,有现成的是不会去推演模板的
}
  • 可以将size_t重载一个int类型就可以解决因为参数类型不同造成的匹配函数错误.

反向迭代器

本身包含正向迭代器,对于正向迭代器的一种封装,重载++--的方向。区别就是++和–的方向是相反的。
正向迭代器的开始就是反向迭代器的结束。

operator*取前一个位置主要就是为了让反向迭代器开始和结束跟正向迭代器对称。

image-20230202214809318

reference operator* const()
{
	Iterator tmp=current;
	return *--tmp;
}

所以以后别的不是链表的反向迭代器都可以像这个一样进行复用。
iterator 是哪个容器的迭代器,reverse_iterator就可以适配哪个容器的反向迭代器.

	template <class Iterator, class Ref, class Ptr>
	class reverse_iterator
	{
		typedef reverse_iterator<Iterator, Ref, Ptr> self;
	public:
		reverse_iterator(Iterator it)
			:_it(it)
		{}

		Ref operator*()
		{
			//return *_it;
			Iterator prev = _it;
			return *--prev;
		}

		Ptr operator->()
		{
			return &operator*();
		}

		self& operator++()
		{
			--_it;
			return *this;
		}

		self& operator--()
		{
			++_it;
			return *this;
		}

		bool operator!= (const self & rit) const
		{
			return _it != rit._it;
		}

	private:
		Iterator _it;
	};

删除节点后,只有指向当前节点的迭代器失效了,其前后的迭代器仍然有效,
因为底层为不连续空间,只有被删除的 节点才会失效
vector由于在头部插入数据效率很低,所以没有提供push_front方法,但是如果需要有insert可以使用.

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

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

相关文章

05_xml

目录0、文档声明1.XML 简介2、xml 的作用&#xff1f;3、xml 语法3.1、文档声明3.2、xml 注释3.3、元素&#xff08;标签&#xff09;3.4、xml 属性3.5、语法规则&#xff1a;3.5.1&#xff09;所有 XML 元素都须有关闭标签&#xff08;也就是闭合&#xff09;3.5.2&#xff09…

uniapp:常用跨端业务组件(ts版本)

插件内组件包含以下功能&#xff1a; 自定义状态栏组件(ZoNavBar)上拉加载状态组件(ZoLoading)弹窗组件(ZoPopup)搜索组件(ZoSearchBar)空数据组件(ZoEmpty)tab标签组件(ZoTabs)tab下拉筛选组件(ZoSelectTabs)底部导航组件(ZoTabBar)cell导航组件(ZoCell) 10.标题内容组件(ZoT…

iptables端口复用后门、sslh

iptables端口复用 创建端口复用链 创建端口复用规则将流量转到22端口 开启开关&#xff0c;接收到一个长为1139的icmp包&#xff0c;则将来源ip添加到LETMEIN表中 如果syn包来源ip处于letmein列表中&#xff0c;则跳转到LETMEIN链处理&#xff0c;有效时间为3600秒 开启复…

c++11 标准模板(STL)(std::multiset)(五)

定义于头文件 <set> template< class Key, class Compare std::less<Key>, class Allocator std::allocator<Key> > class multiset;(1)namespace pmr { template <class Key, class Compare std::less<Key>> usi…

PyQt5编程基础 2.2 信号与槽函数

信号与槽函数信号&#xff08;Signal&#xff09;信号是在特定情况下被发射的一种通告。举例&#xff1a;PushButton的信号是鼠标单击时发射的clicked信号槽&#xff08;Slot&#xff09;对信号相应的函数。举例&#xff1a;Qwidget有一个槽函数&#xff0c;功能是关闭窗口信号…

Uncaught SyntaxError: Unexpected token ... 【bug记录】vue项目发布

项目场景&#xff1a; 项目场景&#xff1a;部署vue项目&#xff0c;组件或页面html使用ES6语法导致&#xff0c;界面无法显示。 客户那边采用了比较低版本的浏览器&#xff0c;自己电脑上却没有出现&#xff0c;也不方便调试测试。 问题描述 打开来控制台&#xff0c;看到异…

单片机开发---ESP32S3移植NES模拟器(一)

书接上文 《单片机开发—ESP32-S3模块上手》 《单片机开发—ESP32S3移植lvgl触摸屏》 参考内容 依旧是参考韦东山老师的作品来移植的 《ESP32|爷青回&#xff01;ESP32(单片机) NES模拟器_NES游戏机掌机教程(开源详细讲解实现代码&#xff01;)》 韦老师已经将代码开源&am…

深入解读神策分析云两大闭环,助力企业全面数字化转型应用

随着市场的发展、客户的深度使用以及全新的产品认知&#xff0c;神策希望能够帮助企业客户构建拥有正向反馈、持续提升、优化经营效率的数据应用闭环。本次&#xff0c;神策在用户行为分析的基础上&#xff0c;对分析云的整体产品架构进行全面升级&#xff0c;不仅包括公私域流…

json字符带有反斜杠\处理

目录说明说明 json字符带有反斜杠\&#xff0c;需要转义处理 <dependency><groupId>org.apache.commons</groupId><artifactId>commons-text</artifactId><version>1.6</version></dependency>String json "{\"n…

解决安装2.4版本的percona-xtrabackup和5.6版本的mysql冲突的问题

问题描述&#xff1a;在阿里云上有一个5.6版本的mysql&#xff0c;想把备份的数据恢复到本地。按照阿里云的文档描述&#xff0c;本机mysql的版本也得是5.6&#xff0c;percona-xtrabackup版本得是2.4。于是开始动手操作&#xff0c;无非是在本机安装5.6版本的mysql和2.4版本的…

【C++】C++11语法 ~ 可变参数模板

&#x1f308;欢迎来到C专栏~可变参数模板 (꒪ꇴ꒪(꒪ꇴ꒪ )&#x1f423;,我是Scort目前状态&#xff1a;大三非科班啃C中&#x1f30d;博客主页&#xff1a;张小姐的猫~江湖背景快上车&#x1f698;&#xff0c;握好方向盘跟我有一起打天下嘞&#xff01;送给自己的一句鸡汤&…

2月3日第壹简报,星期五,农历正月十三

2月3日第壹简报&#xff0c;星期五&#xff0c;农历正月十三坚持阅读&#xff0c;静待花开1. 香港&#xff1a;将向世界各地旅客派发50万张免费机票&#xff0c;3月1日起派发&#xff0c;为期6个月&#xff0c;率先向东南亚地区送出。2. 我国新增18处国际重要湿地&#xff0c;湿…

聚观早报|网易开放暴雪游戏退款申请通道;鱼跃医疗回应被罚270万

今日要闻&#xff1a;网易开放暴雪游戏退款申请通道&#xff1b;谷歌 ChatGPT 竞品搜索设计将迎来大改&#xff1b;“鱼跃医疗”回应被罚270万元&#xff1b;大众考虑在加拿大建设新的电池工厂&#xff1b;微软将把ChatGPT整合到必应搜索中网易开放暴雪游戏退款申请通道 2 月 1…

力扣刷题|654.最大二叉树、617.合并二叉树、700.二叉搜索树中的搜索、98.验证二叉搜索树

LeetCode 654.最大二叉树 题目链接&#x1f517; LeetCode 654.最大二叉树 思路 最大二叉树的构建过程如下&#xff1a; 构造树一般采用的是前序遍历&#xff0c;因为先构造中间节点&#xff0c;然后递归构造左子树和右子树。 class Solution {public TreeNode constructM…

构造http请求的几种方式(附源码)

文章目录前言一、form表单构造http请求二、ajax构造http请求三、Java socket构造http请求总结前言 博主个人社区&#xff1a;开发与算法学习社区 博主个人主页&#xff1a;Killing Vibe的博客 欢迎大家加入&#xff0c;一起交流学习~~ 一、form表单构造http请求 form (表单) 是…

SSH基础知识(一)

SSH基础知识SSH对称加密非对称加密如何生成秘钥如何管理秘钥不同版本ssh命令安装ssh启动ssh服务登录ssh退出ssh登录远程登录执行命令ssh参数端口转发本地转发远程转发动态转发最近有用到SFTP协议完成一些功能开发&#xff0c;这玩意和FTP比较像&#xff0c;当时以为是升级版&am…

FPGA和CPLD芯片选型介绍(二)

FPGA器件选型&#xff08;以Xilinx和Altera为例&#xff09;器件选型是件很严肃的事情&#xff0c;既要考虑性能又要兼顾成本&#xff0c;还要考虑长期供货的稳定性&#xff0c;因此很考验工程师的知识广度储备。一般而言&#xff0c;FPGA&#xff08;CPLD&#xff09;需要分三…

3、Maven——Maven创建java web工程,Maven search插件

目录 一、Maven创建java web工程 二、Maven创建java web项目的结构 1、添加项目目录 2、web.xml配置处理报错 三、IDEA更改XML版本 一、Maven创建java web工程 创建Empty Project空工程&#xff1b;右击Empty Project工程--->New--->Module--->Maven Archetype N…

Linux环境下安装软件合集【2】

Linux环境下安装软件合集【2】 Linux环境下安装软件合集【1】 1 安装tomcat 1.1 安装启动tomcat 下载tomcat压缩包 通过wget方式 wget --no-check-certificate https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.70/bin/apache-tomcat-9.0.70.tar.gz直接官网下载压缩包&…

23k入职腾讯测试岗那天,我哭了,这5个月付出的一切总算没有白费~

先说一下自己的个人情况&#xff0c;计算机专业&#xff0c;16年普通二本学校毕业&#xff0c;经历过一些失败的工作经历后&#xff0c;经推荐就进入了华为的测试岗&#xff0c;进去才知道是接了个外包项目&#xff0c;不太稳定的样子&#xff0c;可是刚毕业谁知道什么外包不外…