赞
踩
STL中List容器底层是一个双向带头循环链表。
这里简单搭建一个List,下面我们不断完善。
思路:
1、List作为一个双向带头链表,所以除了创建一个List类,还需要有一个结点结构体有着可以被外部访问的成员prev、next、data。
2、List应当有一个哨兵结点,所以默认构造必须我们写且初始化一个结点设为哨兵结点。
#pragma once #include <iostream> #include <assert.h> using namespace std; namespace test { template<class T> struct Node { struct Node<T>* _prev; struct Node<T>* _next; T _data; //在后续插入建立新结点,初始化 Node(const T& x = T()) :_prev(nullptr) ,_next(nullptr) ,_data(x) {} }; template<class T> class list { typedef struct Node<T> node; public: void initlist() { _head = new node; _head->_next = _head; _head->_prev = _head; _size = 0; } // 构造 list() { initlist(); } private: node* _head; size_t _size; }; }
C++中的迭代器iterator虽然在使用上可以当成指针一样用,但是对于List如果要像指针一样,那么就需要对iterator的运算符进行重载实现。
那么可以将iterator封装成一个类进行实现。
有了迭代器,list就可以实现begin()和end()对链表结点进行定位。
并且也能在特定位置实现insert。
#pragma once #include <iostream> #include <assert.h> using namespace std; namespace test { template<class T> struct Node { ... }; template<class T> class iterator { typedef struct Node<T> node; public: iterator(node* it) :_node(it) {} //前置 iterator& operator++() { _node = _node->_next; return *this; } //后置 iterator& operator--() { _node = _node->_prev; return *this; } bool operator!=(iterator& it) { return it._node != _node; } T& operator*() { return _node->_data; } node* getnode() { return _node; } private: node* _node; }; template<class T> class list { typedef struct Node<T> node; typedef iterator<T> iterator; public: iterator begin() { return iterator(_head->_next); } iterator end() { return iterator(_head); } void initlist() { _head = new node; _head->_next = _head; _head->_prev = _head; _size = 0; } // 构造 list() { initlist(); } //拷贝构造 template <class InputIterator> list(InputIterator first, InputIterator last) { initlist(); while (first != last) { push_back(*first); ++first; } } iterator insert(iterator pos, const T& x = T()) { node* newnode = new node(x); node* cur = pos.getnode(); node* prev = cur->_prev; prev->_next = newnode; newnode->_prev = prev; newnode->_next = cur; cur->_prev = newnode; _size++; return iterator(newnode); } void push_back(T x = T()) { insert(end(), x); } private: node* _head; size_t _size; }; }
const_iterator
对于const对象,迭代器也需要用const的。
对于const迭代器,不能写成const iterator it 这修饰的是it,需要修饰的iterator所以需要一个新的类型const_iterator
const_iterator保证的是被指向的结点内容不能变化。
下面看两种情况
对于const和非const类型的改变,可以直接通过模板的类型泛型进行更改。
// 同一个类模板实例化出的两个类型 // typedef __list_iterator<T, T&, T*> iterator; // typedef __list_iterator<T, const T&, const T*> const_iterator; template<class T> class list_iterator { typedef struct Node<T> node; public: typedef list_iterator<T, Ref, Ptr> Self list_iterator(node* it) :_node(it) {} //前置 Self& operator++() { _node = _node->_next; return *this; } //后置 Self& operator--() { _node = _node->_prev; return *this; } bool operator!=(list_iterator<T> x) const { return _node != x._node; } /*T& operator*() { return _node->_data; }*/ Ref operator*() { return _node->_data; } Ptr operator->() { return &(_pnode->data); } node* getnode() { return _node; } private: node* _node; };
编译器对it->_col这个位置做了一个优化,本来获取data地址后应该是it->->_col,但是编译器做了优化就是it->_col,但it.operator->()->_col这样不会受影响。
struct Pos { int _row; int _col; Pos(int row = 0, int col = 0) :_row(row) ,_col(col) {} }; void Print_list(const list<Pos>& lt) { list<Pos>::const_iterator it = lt.begin(); while (it != lt.end()) { //我们知道it的底层 //cout << (*it)._col << " " << (*it)._row << endl; //cout << (&(*it))->_row << ":" << (*it)._col << endl; //普通认为是指针 cout << it->_col << " " << it->_row << endl; //cout << it.operator->()->_col << " " << it.operator->()->_row << endl; ++it; } cout << endl; }
反向迭代器就是从链表的尾部到头部。
在底层rend()其实就是begin(),rbegin()其实就是end(),
并且reverse_iterator其实是一个适配器,通过iterator封装的一个类,
所以如果实现了一个容器的正向迭代器,那么反向迭代器就一定能实现。
#include <iostream> #include <assert.h> using namespace std; namespace test { template <class Iterator, class Ref, class Ptr> class ReverseIterator { typedef ReverseIterator<Iterator, Ref, Ptr> self; public: ReverseIterator(Iterator it) :_it(it) {} Ref operator*() { Iterator tmp = _it; return *(--tmp); } Ptr operator->() { return &(operator*()); } self operator++() { --_it; return *this; } self operator--() { ++_it; return *this; } bool operator!=(const self& s) const { return _it != s._it; } private: Iterator _it; }; template <class T> struct ListNode { struct ListNode<T>* _next; struct ListNode<T>* _prev; T data; ListNode(T x = T()) :_next(nullptr) ,_prev(nullptr) ,data(x) {} }; template <class T, class Ref, class Ptr> struct list_iterator { typedef struct ListNode<T> node; typedef struct list_iterator<T, Ref, Ptr> Self; list_iterator(node* p) :_pnode(p) {} bool operator!=(Self x) const { return _pnode != x._pnode; } bool operator==(Self x) const { return _pnode == x._pnode; } Ptr operator->() { return &(_pnode->data); } Ref operator*() { return _pnode->data; } Self& operator++() { _pnode = _pnode->_next; return *this; } Self operator++(int) { Self tmp(*this); _pnode = _pnode->_next; return tmp; } Self& operator--() { _pnode = _pnode->_prev; return *this; } Self operator--(int) { Self tmp(*this); _pnode = _pnode->_prev; return tmp; } node* _pnode; }; template <class T> class list { typedef struct ListNode<T> node; public: //简化类型 typedef list_iterator<T, T&, T*> iterator; 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; iterator begin() { return iterator(_head->_next); } iterator end() { return iterator(_head); } const_iterator begin() const { return const_iterator(_head->_next); } const_iterator end() const { return const_iterator(_head); } reverse_iterator rbegin() { return end(); } reverse_iterator rend() { return begin(); } const_reverse_iterator rbegin() const { return end(); } const_reverse_iterator rend() const { return begin(); } void initlist() { _head = new node; _head->_next = _head; _head->_prev = _head; _size = 0; } //构造 list() { initlist(); } //构造 template <class InputIterator> list(InputIterator first, InputIterator last) { initlist(); while (first != last) { push_back(*first); ++first; } } void swap(list<T>& lt) { std::swap(_head, lt._head); std::swap(_size, lt._size); } list(const list<T>& lt) { initlist(); list<T> tmp(lt.begin(), lt.end()); swap(tmp); } list& operator=(list<T> lt) { swap(lt); return *this; } bool empty() const { return _size == 0; } size_t size() const { return _size; } ~list() { clean(); delete _head; _head = nullptr; } void push_back(T x = T()) { insert(end(), x); } void push_front(T x = T()) { insert(begin(), x); } void pop_back() { erase(--end()); } void pop_front() { erase(begin()); } iterator insert(iterator pos, const T& x = T()) { node* newnode = new node(x); node* cur = pos._pnode; node* prev = cur->_prev; prev->_next = newnode; newnode->_prev = prev; newnode->_next = cur; cur->_prev = newnode; _size++; return iterator(newnode); } iterator erase(iterator pos) { assert(pos != end()); node* cur = pos._pnode; node* prev = cur->_prev; node* next = cur->_next; delete cur; prev->_next = next; next->_prev = prev; _size--; return iterator(next); } void clean() { iterator it = begin(); while (it != end()) { it = erase(it); } } private: node* _head; size_t _size; };
总结:
list迭代器为了重载其多个操作符,所以弄了一个封装类。迭代器在不同场景经过操作符函数返回了不同类型,其中还要区别const类型,通过模板泛型能方便我们应对这些情况。
反向迭代器是对正向迭代器的封装,所以实现了正向迭代器就能实现反向迭代器。
本节完~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。