这里参照库里,不针对某个容器做反向迭代器,我这里主要是模拟反向迭代器的适配器
目录
反向迭代器
#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; }; }