赞
踩
在正式讲解之前,我们先简单的认识一下list
template < class T, class Alloc = allocator<T> > class list;
同样这里有两个模板参数,第一个是实例化的类型,第二个是空间配置器。
库里的list是采用带头双向循环链表进行实现的。
1.输入迭代器
2.输出迭代器
3.单向迭代器——forward_list,unorder_xxx
4.双向迭代器——list/map/set
5.随机访问迭代器——vector/string/deque
之间的关系:
list<int> lt; lt.push_back(1); lt.push_back(2); lt.push_back(3); lt.push_back(4); lt.push_back(5); lt.push_back(6); for (auto e : lt) { cout << e << " "; } cout << endl; list<int>::iterator it = lt.begin(); for (size_t i = 0; i < 5; i++) { it++; } //在第五个位置的前面插入10 //第五个位置——是下标为5,也就是第六个元素。 lt.insert(it,10); for (auto e : lt) { cout << e << " "; } cout << endl;
说明:因为list不支持随机访问,因此没有+,+=,[] 运算符重载,但支持++,- -。
这里的迭代器,在插入之后,并没有失效,因为结点的插入是单个申请,单个释放的。不存在 扩容的现象。
void test_list() { list<int> lt; lt.push_back(2); lt.push_back(2); lt.push_back(3); lt.push_back(4); lt.push_back(90); lt.push_back(6); lt.push_back(7); for (auto e : lt) { cout << e << " "; } cout << endl; //删除所有的偶数结点 list<int>::iterator it = lt.begin(); while (it != lt.end()) { if (*it % 2 == 0) { it = lt.erase(it); } else { it++; } } for (auto e : lt) { cout << e << " "; } cout << endl; }
void test_list() { list<int> lt; lt.push_back(2); lt.push_back(2); lt.push_back(3); lt.push_back(4); lt.push_back(5); lt.push_back(6); lt.push_back(7); for (auto e : lt) { cout << e << " "; } cout << endl; list<int> lt1; lt1.push_back(1); lt1.push_back(3); lt1.push_back(5); lt1.push_back(7); lt1.push_back(9); for (auto e : lt1) { cout << e << " "; } cout << endl; //将lt1合并到lt上 lt.merge(lt1); for (auto e : lt) { cout << e << " "; } cout << endl; }
接口:
void splice (iterator position, list& x);
//将x链表转移到另一条链表的pos位置之前
void splice (iterator position, list& x, iterator i);
//将x链表的某个位置的结点移到另一条链表的pos之前
void splice (iterator position, list& x, iterator first, iterator last);
//将x链表的[first,last)的区间移到另一条链表的pos位置之前。
注意:迭代器/迭代器区间不能重合!
list<int> lt; lt.push_back(2); lt.push_back(2); lt.push_back(3); lt.push_back(4); lt.push_back(5); lt.push_back(6); lt.push_back(7); for (auto e : lt) { cout << e << " "; } cout << endl; list<int> lt1; lt1.push_back(1); lt1.push_back(3); lt1.push_back(5); lt1.push_back(7); lt1.push_back(9); for (auto e : lt1) { cout << e << " "; } cout << endl; //将lt1转移到到lt的前面 lt.splice(lt.begin(),lt1); for (auto e : lt) { cout << e << " "; } cout << endl; //将lt的后半部分转移到lt1上 list<int>::iterator it = lt.begin(); for (size_t i = 0; i < 5; i++) { it++; } lt1.splice(lt1.begin(), lt ,it, lt.end()); for (auto e : lt1) { cout << e << " "; } cout << endl; //将lt1的第一个结点移到lt的最前面 lt.splice(lt.begin(), lt1, lt1.begin()); for (auto e : lt) { cout << e << " "; } cout << endl;
list<int> lt; lt.push_back(2); lt.push_back(1); lt.push_back(3); lt.push_back(4); lt.push_back(2); lt.push_back(6); lt.push_back(4); lt.sort(); for (auto e : lt) { cout << e << " "; } cout << endl; lt.unique(); for (auto e : lt) { cout << e << " "; } cout << endl;
void test_list2() { list<int> lt; vector<int> v; //设置随机数起点 srand((unsigned)time(nullptr)); size_t datas_num = 1000000; for (size_t i = 0; i < datas_num; i++) { int n = rand(); lt.push_back(n); v.push_back(n); } int begin1 = clock(); sort(v.begin(), v.end()); int end1 = clock(); cout <<"vector:" << (end1 - begin1) << endl; int begin2 = clock(); lt.sort(); int end2 = clock(); cout <<"list:" << (end2 - begin2) << endl; }
不与库里面的list冲突
,我们需要命名空间
对自己实现的类进行封装
带头双向循环链表
的数据结构进行实现的。分开讲解
的,最后我会给出源码
。template<class T> struct list_node { list_node(const T& val = T()) :_val(val) ,_next(nullptr) ,_prev(nullptr) {} T _val; list_node* _next; list_node* _prev; }; template<class T> class list { typedef list_node<T> Node; public: private: Node* _head; size_t _size; };
我们先来谈谈是如何实现的,迭代器必然是指向一个结点的指针,但是能完成++操作,以及解引用操作,那该怎么办呢?答案其实很简单——用类进行封装,通过运算符重载实现相应的功能
。
简单的迭代器框架:
template<class T>
struct list_iterator
{
typedef list_iterator<T> iterator;
Node* _node;
};
list_iterator(Node* val = nullptr)
:_node(val)
{}
list_iterator(const iterator& lt)
:_node(lt._node)
{}
剩下的操作是,类里面进行重载++,-- ,*。
//前置
iterator& operator ++()
{
_node = _node->_next;
return *this;
}
//后置
iterator operator ++(int)
{
list_iterator tmp(_node);
_node = _node->_next;
return tmp;
}
//前置
iterator& operator --()
{
_node = _node->_prev;
return *this;
}
//后置
iterator operator --(int)
{
list_iterator tmp(_node);
_node = _node->_prev;
return tmp;
}
T& operator *()
{
return _node->_val;
}
这样迭代器的基本功能就实现了,但是const的迭代器该如何实现呢?
是这样么?
typedef const list_iterator<T> const_iterator;
这样迭代器的成员变量不可被修改,即不可以++或者- -,不符合要求,我们想要的只是返回的值不可被修改。
一般都会再拷贝一份进行,将拷贝的迭代器改改,但是我们还可以设置第二个模板参数,这样外面可以这样定义。
template<class T,class Ref> struct list_iterator;
//里面的运算符重载——*
Ref operator *()
{
return _node->_val;
}
//list里面可以这样定义
typedef list_iterator<T,const T&> const_iterator;
typedef list_iterator<T,T&> iterator;
还有第二个问题,如果迭代器指向的是自定义类型,比如:
struct A
{
A(int x = 0)
:_a1(x)
{}
int _a1;
};
如果想要访问其成员,直接解引用是不行的。
我们可以这样:
iterator it = lt.begin();
(*it)._a1;
访问其元素。
我们还可以重载-> 进行访问:
T* operator ->()
{
return &(_node->_val);
}
iterator it = lt.begin();
it->_a1;
这样其实省略了一个箭头,这省略的一个箭头其实是为了美观,编译器在处理时,会自动加上的。
如果是const对象呢?其实处理方式一样的,再加一个模板参数。
更新后的模板,和迭代器:
template<class T,class Ref,class Ptr> struct list_iterator;
Ptr operator ->()
{
return &(_node->_val);
}
typedef list_iterator<T,const T&,const T*> const_iterator;
typedef list_iterator<T,T&,T*> iterator;
那完整版的迭代器即为:
template<class T,class Ref,class Ptr> //第一个参数:为了确定Node的类型; //第二个是为了实现*解引用的const与非const返回值 //第三个是为实现Node成员为结构体对象的指针的访问对象。 struct list_iterator { typedef list_node<T> Node; typedef list_iterator<T, Ref, Ptr> self; typedef list_iterator<T, T&, T*> iterator; list_iterator(Node* val = nullptr) :_node(val) {} list_iterator(const iterator& lt) :_node(lt._node) {} //重载++ self& operator ++() { _node = _node->_next; return *this; } //后置++,为了区别需要重载一下,这里的参数实际上没啥用 self operator ++(int) { list_iterator tmp(_node); _node = _node->_next; return tmp; } self& operator --() { _node = _node->_prev; return *this; } self operator --(int) { list_iterator tmp(_node); _node = _node->_prev; return tmp; } bool operator != (const self& it) const { return _node != it._node; } bool operator == (const self& it) const//const和非const都能用 { return _node == it._node; } Ptr operator ->() { return &(_node->_val); } Ref operator *() { return _node->_val; } Node* _node; };
iterator begin() { return _head->_next; //隐式类型转换 } const_iterator begin()const { return _head->_next; } iterator end() { return _head; } const_iterator end()const { return _head; }
//在pos之前插入 void insert(iterator pos, const T& val) { Node* newnode = new Node(val); Node* cur = pos._node; Node* prev = cur->_prev; newnode->_next = cur; newnode->_prev = prev; cur->_prev = newnode; prev->_next = newnode; _size++; }
Node* 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; _size--; return next; }
void push_back(const T& val)
{
//Node* tail = _head->_prev;
//Node* newnode = new Node(val);
//newnode->_next = _head;
//newnode->_prev = tail;
//_head->_prev = newnode;
//tail->_next = newnode;
insert(end(), val);
}
void push_front(const T& val)
{
insert(begin(), val);
}
void pop_front()
{
erase(begin());
}
void pop_back()
{
erase(--end());
}
//默认构造函数 list() { _head = new Node; _head->_next = _head; _head->_prev = _head; _size = 0; } //拷贝构造 list(const list<T>& lt) { _head = new Node; _head->_next = _head; _head->_prev = _head; _size = 0; for (auto e : lt) { push_back(e); } }
void clear()
{
iterator it = begin();
while (it != end())
{
it = erase(it);
}
}
~list()
{
clear();
delete _head;
}
void swap(list &tmp)
{
std::swap(_head, tmp._head);
std::swap(_size, tmp._size);
}
list& operator = (list tmp)
{
swap(tmp);
return *this;
}
剩余的接口,过于简单,这里就不再列出了,有兴趣请看源码。
namespace my_list { template<class T> struct list_node { list_node(const T& val = T()) :_val(val) ,_next(nullptr) ,_prev(nullptr) {} T _val; list_node* _next; list_node* _prev; }; template<class T,class Ref,class Ptr> struct list_iterator { typedef list_node<T> Node; typedef list_iterator<T, Ref, Ptr> self; typedef list_iterator<T, T&, T*> iterator; //这个看着确实有点奇怪,写这个为了实现const_iterator转换为 //非const_itertaor,从而达到类型转换的效果。 list_iterator(Node* val = nullptr) :_node(val) {} list_iterator(const iterator& lt) :_node(lt._node) {} //重载++ self& operator ++() { _node = _node->_next; return *this; } //后置++,为了区别需要重载一下,这里的参数实际上没啥用 self operator ++(int) { list_iterator tmp(_node); _node = _node->_next; return tmp; } self& operator --() { _node = _node->_prev; return *this; } self operator --(int) { list_iterator tmp(_node); _node = _node->_prev; return tmp; } bool operator != (const self& it) const { return _node != it._node; } bool operator == (const self& it) const//const和非const都能用 { return _node == it._node; } Ptr operator ->() { return &(_node->_val); } //加上迭代器为it则调用此函数在底层上实际被翻译为 //(it.operator->())->结构体成员,忽略了一个->,看起来更加的美观。 Ref operator *() { return _node->_val; } Node* _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; list() { _head = new Node; _head->_next = _head; _head->_prev = _head; _size = 0; } list(const list<T>& lt) { _head = new Node; _head->_next = _head; _head->_prev = _head; _size = 0; for (auto e : lt) { push_back(e); } } ~list() { clear(); delete _head; } void clear() { iterator it = begin(); while (it != end()) { it = erase(it); } //cout << _size << endl; } iterator begin() { //return _head->_next; //隐式类型转换为list_itertor return _head->_next; } const_iterator begin()const { //return _head->_next; //隐式类型转换为list_itertor return _head->_next; } iterator end() { return _head; //返回的是_head的拷贝,因此返回对象具有常属性 //隐式类型转换为list_itertor //return itrator(_head->next); //匿名对象 } const_iterator end()const { return _head; //返回的是_head的拷贝,因此返回对象具有常属性 //隐式类型转换为list_itertor //return itrator(_head->next); //匿名对象 } void push_back(const T& val) { //Node* tail = _head->_prev; //Node* newnode = new Node(val); //newnode->_next = _head; //newnode->_prev = tail; //_head->_prev = newnode; //tail->_next = newnode; insert(end(), val); } //在pos之前插入 void insert(iterator pos, const T& val) { Node* newnode = new Node(val); Node* cur = pos._node; Node* prev = cur->_prev; newnode->_next = cur; newnode->_prev = prev; cur->_prev = newnode; prev->_next = newnode; _size++; } Node* 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; _size--; return next; } void pop_back() { erase(--end()); } void pop_front() { erase(begin()); } void push_front(const T& val) { insert(begin(), val); } size_t size() { return _size; } bool empty() { return _size == 0; } void swap(list &tmp) { std::swap(_head, tmp._head); std::swap(_size, tmp._size); } list& operator = (list tmp) { swap(tmp); return *this; } private: Node* _head; size_t _size; }; }
今天的分享就到这里了,如果觉得文章不错,点个赞鼓励一下吧!我们下篇文章再见
!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。