list容器简介
- list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
- list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
- list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,以让其更简单高效。
- 与其他的序列式容器相比,list通常在任意位置进行插入、移除元素的执行效率更好。
- 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问。
- list还需要一些额外的空间,以保存每个节点的相关联信息。
list容器使用
(1)构造函数
- list():构造空list
- list(size_type n, const value_type& val = value_type()):构造list中包含n个val
- list(const list& x):拷贝构造
- list(InputIterator first, InputIterator last):用(first, last)区间中的元素构造list
#include<iostream>
#include<list>
using namespace std;
int main()
{
list<int> l1;
list<int> l2(4, 100);
list<int> l3(l2.begin(), l2.end());
list<int> l4(l3);
int arr[] = {1, 2, 3, 4, 5};
list<int> l5(arr, arr + sizeof(arr)/sizeof(int));
for(list<int>::iterator it = l5.begin(); it != l5.end(); ++it)
{
cout<<*it<<" ";
}
cout<<endl;
for(auto& x : l5)
{
cout<<x<<" ";
}
cout<<endl;
return 0;
}
(2)迭代器iterator
- begin()+end():获取第一个数据位置的iterator/const_iterator,获取最后一个数据的下一个位置的iterator/const_iterator
- rbegin()+rend():获取最后一个数据位置的reverse_iterator,获取第一个数据的前一个位置的reverse_iterator
#include<iostream>
#include<list>
using namespace std;
void PrintList(const list<int>& li)
{
for(list<int>::const_iterator cit = li.begin(); cit != li.end(); ++cit)
{
cout<<*cit<<" ";
}
cout<<endl;
}
int main()
{
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
list<int> li(arr, arr + sizeof(arr)/sizeof(int));
//iterator
for(list<int>::iterator it = li.begin(); it != li.end(); ++it)
{
cout<<*it<<" ";
}
cout<<endl;
//reverse_iterator
for(list<int>::reverse_iterator rit = li.rbegin(); rit != li.rend(); ++rit)
{
cout<<*rit<<" ";
}
cout<<endl;
//const_iterator
PrintList(li);
return 0;
}
(3)容量空间
- empty()
- size()
(4)元素接口
- front:返回list的第一个节点中值的引用
- back:返回list的最后一个节点中值的引用
(5)增删查改
- push_front()
- pop_front()
- push_back()
- pop_back()
- insert(iterator pos, value_type val):在pos之前插入val
- erase(iterator pos):删除pos数据
- swap():交换两个list中的元素
- clear()
#include<iostream>
#include<algorithm>
#include<list>
#include<vector>
using namespace std;
void PrintList(const list<int>& li)
{
for(auto x : li)
{
cout<<x<<" ";
}
cout<<endl;
}
int main()
{
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
list<int> li(arr, arr + sizeof(arr)/sizeof(int));
PrintList(li);
li.push_front(10);
li.push_back(20);
PrintList(li);
li.pop_front();
li.pop_back();
PrintList(li);
/*
list<int>::iterator pos = find(li.begin(), li.end(), 3);
cout<<*pos<<endl;
*/
auto pos = ++li.begin();
cout<<*pos<<endl;
li.insert(pos, 100);
PrintList(li);
li.insert(pos, 5, 200);
PrintList(li);
vector<int> v{300, 301, 302};
li.insert(pos, v.begin(), v.end());
PrintList(li);
li.erase(pos);
PrintList(li);
list<int> tmp(li);
li.erase(li.begin(), li.end());
PrintList(li);
PrintList(tmp);
list<int> l{12, 23, 34, 45, 56};
PrintList(l);
PrintList(tmp);
l.swap(tmp);
PrintList(l);
PrintList(tmp);
cout<<l.size()<<endl;
return 0;
}
(6)迭代器失效问题
迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。
#include<iostream>
#include<list>
using namespace std;
void PrintList(const list<int>& li)
{
for(auto it = li.begin(); it != li.end(); ++it)
{
cout<<*it<<" ";
}
cout<<endl;
}
int main()
{
list<int> li{12, 23, 34, 45, 56, 67, 78};
PrintList(li);
/*
* 本段程序会崩溃
* erase执行后,it所指节点已经被删除,导致it失效
* 在下一次使用时,必须先赋值
for(auto it = li.begin(); it != li.end(); ++it)
{
li.erase(it);
}
*/
for(auto it = li.begin(); it != li.end();)
{
it = li.erase(it);
}
PrintList(li);
return 0;
}