什么是list
简单的理解:它的底层就是带头双向循环链表
所以他不支持随机访问,也就是operator[ ]重载
一些函数接口的基本使用
和vector基本类似,这里就不详细说了
list<int> lt1; //无参构造
list<int> lt2(10, 5); // 10个5
list<int> lt3(lt2); //拷贝构造
list<int> lt4(lt2.begin(), lt2.end()); //迭代器区间去构造
其实关于正向和反向的迭代器,
正向的迭代器 ++ ,其实他是向后走
反向的迭代器++,他是向前走
void test1()
{
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
list<int>::iterator it = lt.begin();
while (it != lt.end())
{
cout << *it << " ";
it++;
}
cout << endl;
list<int>::reverse_iterator rit = lt.rbegin();
while (rit != lt.rend())
{
cout << *rit <<" ";
rit++;
}
cout << endl;
}
关于迭代器的详细说明
其实迭代器按功能分类,一共有5种:输入,输出,向前(单向),双向,随机访问
我们需要掌握的就是常见的三种
1,单向:只支持向前走 ++ , 单链表(forward_list)
2, 双向:向前,向后都可以 ++, – 双向循环链表(list)
3, 随机访问:权限最大,都支持 数组和字符串vector,string
从算法()中使用sort(排序),find(查找),reverse(逆置)。
也就是说find()支持 单向,双向,随机访问
sort()只支持 随机访问
reverser 支持随机访问 和双向
可以这样尝试理解一下(随机访问 > 双向 > 单向 > 输入/输出)
void test2()
{
vector<int> v;
v.push_back(3);
v.push_back(10);
v.push_back(1);
v.push_back(0);
sort(v.begin(), v.end());
PrintCon(v); //打印升序 0 1 3 10
sort(v.begin(), v.end(), greater<int>()); //这greater<int>()需头文件<algorithm>
PrintCon(v); //打印降序 10 3 1 0
}
关于list迭代器失效的说明
vector 插入的时候,迭代器会失效,而list不会
vector 删除的时候,迭代器会失效,list也会
为什么呢?
list的模拟实现
首先,关于迭代器,因为原生指针不满足迭代器的要求,所以我们需要将迭代器封装成一个类对象,通过运算符的重载来实现
迭代器的各个功能要求。
迭代器的模拟实现
先看看大致的框架
迭代器是类对象,这里模拟实现的迭代器不是指针了,而是一个类对象(内置类型)
template <class T,class Ref, class Ptr>
struct _list_iterator
{
typedef _list_node<T> node;
typedef _list_iterator<T,Ref,Ptr> sef;
node* _pnode;
_list_iterator(node* newnode = nullptr)
{
_pnode = newnode;
}
//*it --->返回引用
Ref operator*()
{
return _pnode->_val;
}
bool operator==(const sef& s)
{
return _pnode == s._pnode;
}
bool operator!=(const sef& s)
{
return _pnode != s._pnode;
}
//++it 前置++,后置++形参多个int用来区分
sef& operator++()
{
_pnode = _pnode->next;
return *this;
}
};
迭代器的模拟
```cppiterator begin()
{
return iterator(_head->next);
}
iterator end()
{
return iterator(_head);
}
const_iterator begin() const
{
return iterator(_head->next);
}
const_iterator end() const
{
return iterator(_head);
}
任意位置的插入insert()和 删除erase()
首先,list插入后,迭代器是不会失效的,因为迭代器模拟的是节点的指针,我们插入的时候,节点的指针是不做修改的。
list删除后,迭代器肯定是失效了,因为节点都销毁了,已经没有意义了。
void push_bcak(const T& val)
{
//node* newnode = new node(val);
//node* tail = _head->pre;
//tail->next = newnode; //链接newnode和tail
//newnode->pre = tail;
//newnode->next = _head; //链接newnode 和_head
//_head->pre = newnode;
insert(end(), val);
}
void push_front(const T& val)
{
insert(begin(), val);
}
//在pos的前面位置插入val
void insert(iterator pos, const T& val)
{
node* newnode = new node(val);
node* prenode = pos._pnode->pre;
prenode->next = newnode;
newnode->pre = prenode;
newnode->next = pos._pnode;
pos._pnode->pre = newnode;
}
iterator erase(iterator pos)
{
node* cur = pos._pnode;
node* save = cur->next;
save->pre = cur->pre;
cur->pre->next = save;
delete[] cur;
return iterator(save);
}
void pop_back()
{
erase(end());
}
void pop_front()
{
erase(begin());
}
构造函数,拷贝构造,赋值重载,析构
list()
{
_head = new node;
_head->next = _head;
_head->pre = _head;
}
//lt1(lt2)
list(const list<T>& lt2)
{
_head = new node;
_head->next = _head;
_head->pre = _head;
//取出lt2的每个节点赋值给e,
//而迭代器是一个类对象,这样的赋值就内置类型的赋值
for (auto e : lt2)
{
push_bcak(e);
}
}
list& operator=(list<T> lt)
{
swap(_head,lt._head);
return *this;
}
~list()
{
clear();
delete _head;
}