反向迭代器(补充了vector和list)

这里参照库里,不针对某个容器做反向迭代器,我这里主要是模拟反向迭代器的适配器

目录

反向迭代器

 list补充

vector补充


反向迭代器

#pragma once

//首先是关于反向迭代器,第一个参数是传的正向迭代器类型,第二个参数是解引用的时候需要返回的内容
//根据返回的内容,传入即可。
//第三个参数,是用来->返回数据的,因为外面对迭代器的解引用是有规定的
//我们需要返回的是一个数据类实例化对象,不管是自定义类型还是内置类型
//注意,反向迭代器中,我们为了对称,习惯把rbegin==end,rend==begin,也就是说反向迭代器
//解引用的实际是对应正向迭代器的前一个
template<class Iterator,class Ref,class Ptr>
class ReverseIterator
{
public:
	typedef ReverseIterator<Iterator,Ref,Ptr> Self;
	//节省代码长度
	Iterator cur;
	//是正向迭代器对象
	ReverseIterator(Iterator it)
		:cur(it)
	{
		//构造函数,方便其他容器调用和实例化
	}

	//前置++,注意,反向迭代器的++对于正向迭代器来说就是--
	Self& operator++()
	{
		--cur;
		return *this;
	}
	//后置++,同理,注意,返回的是一个局部对象,不能加&
	Self operator++(int)
	{
		Self tmp = *this;
		--cur;
		return tmp;
	}

	//前置--,类似,--即++
	Self& operator--()
	{
		++cur;
		return *this;
	}
	//后置--,类似,注意不加&
	Self operator--(int)
	{
		Self tmp = *this;
		cur++;
		return tmp;
	}

	//注意,我们返回的是一个解引用之后的结果,这个结果本身在tmp=cur中,是浅拷贝,而不是深拷贝
	//也就是说*tmp==*cur,且两者解引用后结果的地址是相同的,所以不影响外面我们传Ref的时候传T&
	Ref operator*()
	{
		Iterator tmp = cur;
		--tmp;
		return *tmp;
	}

	//最上面有讲,巧妙借用下上面写的*重载
	Ptr operator->()
	{
		return &(operator*());
	}

	//不等于,直接套壳,因为正向迭代器已经有了
	bool operator!=(const Self& s)
	{
		return cur != s.cur;
	}
	//等于,同上
	bool operator==(const Self& s)
	{
		return cur == s.cur;
	}
};

 list补充

#pragma once
#include<assert.h>
#include"ReverseIterator.h"
namespace manba {
	//注意,这个是节点的类,我们实现的是双向带头链表,所以要有前驱和后驱
	template<class T>
	struct ListNode {
		ListNode<T>* _next;//前驱
		ListNode<T>* _prev;//后驱
		//注意<>在类里面,是可以忽略的,但我们严谨一些
		T _data;//存数据
		ListNode(const T& x=T())//默认构造函数,方便后面调用,因为不确定参数类型,所以默认值
			//直接用T类型的默认构造即可,不管是内置还是自定义都可以符合
			:_next(nullptr)
			, _prev(nullptr)
			, _data(x)
		{}
	};
	
	//这里通过Ref,第二个模板参数,简约的实现了const迭代器和正常迭代器的转换
	//ptr控制的是配合重载->,区分const迭代器和普通迭代器
	template<class T,class Ref,class Ptr>
	struct _list_iterator {
		typedef ListNode<T> Node;
		//注意,类名<T>才是一个链表节点类型,这里重命名一下,方便后面少写点
		typedef _list_iterator<T,Ref,Ptr> self;
		//跟上面一个同理,这里是一个链表迭代器类型
		Node* _node;
		//迭代器本质还是指针,只是因为原始指针针对物理空间不连续的容器,无法实现++
		//而我们无法重载指针,所以我们采用封装的方式,将指针封装起来,将封装起来的迭代器
		//重载前后置++,前后置--,解引用*等运算符,理由前驱后驱指针,实现向前向后走


		_list_iterator(Node* node)//这里是默认构造,方便各种调用
			:_node(node)
		{}


		//前置++
		self& operator++()
		{
			_node = _node->_next;
			return *this;
		}
		
		//后置++
		//注意,这里我们返回的时候不用&,因为tmp是局部变量,函数结束后会销毁,所以直接返回迭代器类型
		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;
		}

		//解引用,利用ref,实现const迭代器和普通迭代器
		Ref operator*()
		{
			return _node->_data;
		}
		//不等于
		bool operator !=(const self& s)
		{
			return _node != s._node;
		}
		//等于
		bool operator==(const self& s)
		{
			return _node == s._node;
		}
		Ptr operator->()
		{
			return &_node->_data;
		}
		/*struct AA {
			int b;
			AA(int a = 1)
				:b(a)
			{

			}
		};*/
		/*manba::List<manba::AA> l1;
		l1.push_back(3);
		l1.push_back(7);
		l1.push_back(9);
		l1.push_back(12);
		manba::List<manba::AA>::iterator it = l1.begin();
		while (it != l1.end())
		{

			cout << it.operator->()->b << endl;
			cout<<it->b<<endl;
			it++;
		}
		cout << endl;*/
	};

	//const迭代器
	//template<class T>
	//struct _list_const_iterator {
	//	typedef ListNode<T> Node;
	//	//注意,类名<T>才是一个链表节点类型,这里重命名一下,方便后面少写点
	//	typedef _list_const_iterator<T> self;
	//	//跟上面一个同理,这里是一个链表迭代器类型
	//	Node* _node;
	//	//迭代器本质还是指针,只是因为原始指针针对物理空间不连续的容器,无法实现++
	//	//而我们无法重载指针,所以我们采用封装的方式,将指针封装起来,将封装起来的迭代器
	//	//重载前后置++,前后置--,解引用*等运算符,理由前驱后驱指针,实现向前向后走


	//	_list_const_iterator(Node* node)//这里是默认构造,方便各种调用
	//		:_node(node)
	//	{}



	//	//前置++
	//	self& operator++()
	//	{
	//		_node = _node->_next;
	//		return *this;
	//	}

	//	//后置++
	//	//注意,这里我们返回的时候不用&,因为tmp是局部变量,函数结束后会销毁,所以直接返回迭代器类型
	//	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;
	//	}

	//	//解引用
	//	const T& operator*()
	//	{
	//		return _node->_data;
	//	}
	//	//不等于
	//	bool operator !=(const self& s)
	//	{
	//		return _node != s._node;
	//	}
	//	//等于
	//	bool operator==(const self& s)
	//	{
	//		return _node == s._node;
	//	}
	//};
	template<class T>
	class List {
		typedef ListNode<T> Node;
	public:
		
		typedef _list_iterator<T,T&,T*> iterator;
		//typedef _list_const_iterator<T> const_iterator;
		
		//这里迭代器直接传const类型的模板参数
		typedef _list_iterator<T, const T&,const T*> const_iterator;

		//加上这两条即可配合我写的反向迭代器头文件,实现反向迭代器
		typedef ReverseIterator<iterator, T&, T*> reverse_iterator;
		typedef ReverseIterator<const_iterator,const T&,const T*> const_reverse_iterator;
		//跟上面一样
		//空链表初始化
		void empty_init() {
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
		}
		//默认构造函数
		List() {
			empty_init();
		}
		//拷贝构造函数
		//List(const List<T> &cp)
		List(List<T>& cp)
		{
			empty_init();
			for (const auto& e : cp)
			{
				push_back(e);
			}
		}

		//交换函数,交换物理地址
		void swap(List<T>&t)
		{
			std::swap(_head, t._head);
		}
		//赋值
		//第一种
		//List<T>& operator=(const List<T>& t2)
		/*List<T>& operator=( List<T>& t2)
		{
			
			if (this != &t2)
			{
				clear();
				for (const auto& e : t2)
				{
					push_back(e);
				}
			}
			return *this;
		}*/
		//第二种
		//这个方法的妙处在于,因为外面要赋值的链表是直接通过拷贝构造直接给了t2链表
		// ,也就是传值。
		//而拷贝构造我们用的是深拷贝,这样t2的空间和外面的类是不一样的,如此,直接
		//让this链表和t2交换,函数结束之后,t2作为局部变量,t2会自动调用析构函数。
		List<T>& operator=(List<T> t2)
		{
			swap(t2);
			return *this;
		}

		//返回第一个有效节点的迭代器
		iterator begin()
		{
			return _head->_next;
		}

		iterator end()
		{
			return _head;
		}
		//返回第一个有效节点的const迭代器
		const_iterator cbegin() const
		{
			return _head->_next;
		}

		const_iterator cend() const
		{
			return _head;
		}

		//注意,rbegin==end,begin==rend,主要是为了对称,rbegin设为最后一个数据也可以
		reverse_iterator rbegin()
		{
			//这里是巧妙借用反向迭代器类的构造函数
			return reverse_iterator(end());
		}
		reverse_iterator rend()
		{
			return reverse_iterator(begin());
		}
		const_reverse_iterator crbegin() const
		{
			return const_reverse_iterator(cend());
		}
		const_reverse_iterator crend()const
		{
			return const_reverse_iterator(cbegin());
		}
		//尾插
		void push_back(const T& x)
		{
			insert(iterator(_head), x);
		}
		//头插
		void push_front(const T& x)
		{
			insert(begin(), x);
		}
		//尾删
		void pop_back()
		{
			erase(--end());
		}
		//头删
		void pop_front()
		{
			erase(begin());
		}

		//在指定位置前面插入
		//vector 迭代器在insert会失效,list不会
		iterator insert(iterator pos, const T& x)
		{
			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* newnode = new Node(x);
			prev->_next = newnode;
			newnode->_prev = prev;
			newnode->_next = cur;
			cur->_prev = newnode;
			return iterator(newnode);
		}
		//删除指定位置
		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;
			return next;
		}  
		//注意,vector在insert和erase处都会有迭代器失效的风险,所以要注意返回值。
		//而list在insert处不会,不用担心,但是erase处就要考虑这个问题了,要注意接收返回值。
		//更详细的,可以参考我在vector文章里,vector的模拟中对insert和erase的模拟。
		//另外补充一下,vector处的erase会出现迭代器失效,主要是针对vs的强制检查和如果删除了最后一个
		//元素,会导致迭代器超出了数组有效范围。
		//而对于list的erase,因为链表底层物理不一定是连续的,这样原迭代器封装的指针指向的空间是非法空间,
		//所以要注意返回值。

		//清空链表
		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);
			}
		}

		//析构函数
		~List()
		{
			clear();
			delete _head;
			_head = nullptr;
		}
	private:
		Node* _head;
		//头结点,注意,整个list是左闭右开,head是也是end()返回的

	};
	
}

vector补充

 跟list补充的内容是类似的,我就不加额外注释了

#pragma once
#include<string.h>
#include<assert.h>
#include"ReverseIterator.h"
namespace zl
{
	//模板,根据传的类型,决定生成什么类型的模板
	template<class T>
	class vector
	{
	public:
		//定义迭代器
		typedef T* iterator;
		typedef const T* const_iterator;
		//构造函数,赋值空,如果继续优化,可以直接在private那边的变量声明中将变量的缺省值直接设置为空
		//这样无参构造和下面没有被注释的拷贝构造,不用赋值这三个变量了

		typedef ReverseIterator<iterator, T&, T*> reverse_iterator;
		typedef ReverseIterator<const_iterator,const T&, const T*> const_reverse_iterator;
		vector()
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{}
		/*vector(const vector<T>&v)
		{
			_start = new T[v.capacity()];
			memcpy(_start, v._start, sizeof(T) * v.size());
			_finish = _start + v.size();
			_end_of_storage = _start + v.capacity();
		}*/
		//拷贝构造
		vector(const vector<T>& v)
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{
			reserve(v.capacity());//只用扩容一次
			for (auto& e : v)
			{
				push_back(e);
			}
		}
		//泛型的利用迭代器区间初始化(普通数组也可以通过给指针的形式,因为指针是天然的迭代器,物理上连续,注意其他容器的迭代器不一定是指针)
		template<class InputIterator>
		vector(InputIterator first, InputIterator end)
		{
			while (first != end)
			{
				push_back(*first);
				first++;
			}
		}
		//匹配问题所以我们要加个int类型的
		vector ( size_t n, const T& val = T())
		{
			resize(n, val);
		}
		vector(int n, const T& val = T())
		{
			resize(n, val);
		}
		//交换
		void swap(vector<T>& v)
		{
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_end_of_storage, v._end_of_storage);
		}
		//赋值,注意,不能引用,因为我们是拷贝,不是交换
		vector<T>& operator=(vector<T> v)
		{
			swap(v);
			return *this;
		}
		//两个经典开头和结尾,注意,左闭右开
		iterator begin()
		{
			return _start;
		}
		iterator end()
		{
			return _finish;
		}
		//为了防止传const修饰的实体类
		const_iterator cbegin()const
		{
			return _start;
		}
		const_iterator cend()const
		{
			return _finish;
		}
		reverse_iterator rbegin()
		{
			return reverse_iterator(end());
		}
		reverse_iterator rend()
		{
			return reverse_iterator(begin());
		}
		const_reverse_iterator crbegin() const
		{
			return const_reverse_iterator(cend());
		}
		const_reverse_iterator crend() const
		{
			return const_reverse_iterator(cbegin());
		}
		//尾插,注意扩容
		void push_back(const T& x)
		{
			if (_finish == _end_of_storage)
			{
				size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newcapacity);
			}
			*_finish = x;
			++_finish;
		}
		//经典操作,--即可
		void pop_back()
		{
			assert(size() > 0);
			--_finish;
		}
		//这里我们要注意如果发生了扩容,pos迭代器会失效(我们这里vector迭代器是指针,也就是说pos变成了野指针)
		//所以要用len记录长度,从而更新pos
		iterator insert(iterator pos,const T& x)
		{
			assert(pos >= _start);
			assert(pos <= _finish);
			if (_finish == _end_of_storage)
			{
				size_t len = pos - _start;
				reserve(capacity() == 0 ? 4 : capacity() * 2);
				pos = _start + len;
			}
			//memmove(pos + 1, pos, sizeof(T) * (_finish - pos));
			// 这里也有问题,浅拷贝
			//我们要用深拷贝,否则自定义类型会出事
			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;
			}
			*pos = x;
			_finish++;
			return pos;
			//返回值的原因看下面erase的,也是迭代器失效的问题
			//本质除了环境强制检查外,就是存储数据的空间发生了变化,造成的迭代器失效
		}
		iterator erase(iterator pos)
		{
			assert(pos >= _start);
			assert(pos < _finish);
			iterator it = pos + 1;
			while (it < _finish)
			{
				*(it - 1) = *it;
				it++;
			}
			_finish--;
			return pos;
			//注意,为什么要有返回值?
			//因为在我们这个版本中erase的删除是不采取缩容实现。
			//何为缩容实现,比如1 3 5 6,我们删了5,缩容实现就是
			//将1 3 6放在一个新的空间里,而不是如我们现在这样写的
			//在原空间上向前覆盖的形式
			//那这样,如果pos迭代器我们在外面还会继续使用
			//就像reserve那一样,是会出现迭代器失效的问题。
			//还有,如果在vs环境下,会强制检查迭代器,假如
			//迭代器放入了erase,insert这些函数中,那么就不能再用
			//vs会直接强制检查。
			//因此,我们采用返回值的形式,这样不管是强制检查,还是采取缩容
			//我们都可以利用返回值重新覆盖外面pos迭代器的方式来完成我们的代码
		}

		//注意,c++为了兼容模板,升级了内置类型,内置类型也有构造函数
		//因为不确定里面T到底什么类型,所以缺省值,我们干脆用相应的无参构造即可
		void resize(size_t n, T val = T())
		{
			if (n > size())
			{
				reserve(n);
				while (_finish < _start + n)
				{
					*_finish = val;
					_finish++;
				}
			 }
			else
			{
				_finish = _start + n;
			}
		}
		//扩容操作,注意申请的新空间,记得把之前的东西复制过来
		void reserve(size_t n)
		{
			if (n > capacity())
			{
				size_t _size = size();
				T* tmp = new T[n];
				if (_start)
				{
					//memcpy(tmp, _start,  _size* sizeof(T));这个没法处理自定义类型(像string这样内部很可能有指针指向其他空间)
					//也就是浅拷贝和深拷贝的问题
					for (int i = 0; i < _size; i++)
					{
						tmp[i] = _start[i];
						//如果是自定义类型,会调用赋值操作符,并且都是深拷贝(像std这样都是有考虑深拷贝的)
						//如果用内存池,利用定位new,显示调用构造函数,也可以做到
					}
				}

				delete[] _start;
				_start = tmp;
				_finish = _start + _size;
				_end_of_storage = _start + n;
			}
		}
		//经典size,有效数据个数
		size_t size() const
		{
			return _finish - _start;
		}
		//容量
		size_t capacity()const
		{
			return _end_of_storage-_start;
		}
		//经典[]操作符重载
		T& operator[](size_t pos)
		{
			assert(pos < size());
			return *(_start + pos);
		}
		//可读不可改
		const T& operator[](size_t pos) const
		{
			assert(pos < size());
			return *(_start + pos);
		}
		//析构函数
		~vector()
		{
			if (_start)
			{
				delete[] _start;
				_start = _finish = _end_of_storage = nullptr;
			}
		}
	private:
		//开始,结束,容量
		iterator _start;
		iterator _finish;
		iterator _end_of_storage;
	};

}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
vector反向迭代器是一种用于反向遍历vector容器的迭代器。根据引用中的内容,vector反向迭代器的实现包括rbegin()和rend()两个函数。其中,rbegin()函数返回的是正向迭代器的end()适配得到的反向迭代器,它指向vector的最后一个元素;而rend()函数返回的是正向迭代器的begin()适配得到的反向迭代器,它指向vector的第一个元素的前一个位置。 为了更好地理解反向迭代器的使用,可以参考引用中提供的示例代码。在这个示例代码中,首先创建了一个vector容器v,并向其中添加了一些元素。然后通过使用迭代器vit遍历vector容器的元素,将元素依次输出。需要注意的是,迭代器vit在遍历时是从v的begin()开始,直到v的end()之前的位置。因此,输出的结果是按照元素的正序输出。 通过引用中提供的示例代码,可以了解到如何使用反向迭代器来遍历vector容器的元素。在这个示例代码中,首先创建了一个vector容器v1,并向其中添加了一些元素。然后,定义了一个迭代器对象v1_Iter和一个常量反向迭代器v1_rIter。其中,v1_Iter用于正向遍历vector容器的元素,v1_rIter用于反向遍历vector容器的元素。 通过以上的解释和示例代码,可以得出结论:vector反向迭代器是一种用于反向遍历vector容器的迭代器,它可以让我们从最后一个元素开始遍历vector容器的元素。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [【C++之容器适配器】反向迭代器的实现](https://blog.csdn.net/m0_63019745/article/details/129051964)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [vector反向迭代器(reverse_iterator)](https://blog.csdn.net/weixin_43621608/article/details/103750076)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值