C++初级-list容器
1.list容器简介
-
list可以在常数范围内的任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代
-
list底层为双向链表结构,链表中的每个元素存储在互不相关的独立节点中,在节点中通过指针指向前一个和后一个元素
-
list与forward_list非常相似:不同点在于forward_list是单列表,只可向前迭代
-
与其他序列容器相比,list在任意位置进行插入和删除元素时的执行效率更好
-
与其他序列容器相比,list与forward_list的最大缺陷在于不支持任意位置的随机访问
-
list还需要一些额外的空间,以保存每个节点的相关联信息
2.list容器的使用
(1)构造函数 -
list():构造空list
-
list(size_type n,const value_type&val=value_type()):构造list的中包含n个val
-
list(const list& x):拷贝构造
-
list(Inputlterator first,Inputlterator last):用(first,last)区间中的元素构造list
#include<iostream>
#include<list>
using namespace std;
int main()
{
//构造空
list<int> l1;
//构造的list中包含有3个10
list<int> l2(3, 10);
//利用迭代器构造
list<int> l3(l2.begin(), l2.end());
//拷贝构造
list<int> l4(l3);
for (auto x : l4)
{
cout << x << " ";
}
cout << endl;
//利用迭代器构造
int arr[] = { 1,2,3,4 };
list<int> l5(arr, arr + sizeof(arr) / sizeof(int));
for (list<int>::iterator it = l5.begin(); it != l5.end(); it++)
{
cout << *it << " ";
}
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>& l1)
{
for (list<int>::const_iterator cit = l1.begin(); cit != l1.end(); cit++)
{
cout << *cit << " ";
}
}
int main()
{
int arr[] = { 1,2,3,4,5,6 };
list<int> l1(arr, arr + sizeof(arr) / sizeof(int));
//正向
for (list<int>::iterator it = l1.begin(); it != l1.end(); it++)
{
cout << *it << " ";
}
cout << endl;
//反向
for (list<int>::reverse_iterator rit = l1.rbegin(); rit != l1.rend(); rit++)
{
cout << *rit << " ";
}
cout << endl;
//const_iterator
PrintList(l1);
cout << endl;
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<list>
#include<vector>
using namespace std;
void PrintList(const list<int>& l1)
{
for (auto x : l1)
{
cout << x << " ";
}
cout << endl;
}
int main()
{
int arr[] = { 1,2,3,4 };
list<int> l1(arr, arr + sizeof(arr) / sizeof(int));
PrintList(l1);
l1.push_back(5);//尾插
l1.push_front(8);//头插
PrintList(l1);
l1.pop_back();//尾删
l1.pop_front();//头删
PrintList(l1);
/*
list<int>::iterator pos = find(l1.begin(), l1.end(), 2);
cout << *pos << endl;
*/
auto pos = ++l1.begin();
cout << *pos << endl;//获取pos位置(2)
l1.insert(pos, 100);//在pos前增加100
PrintList(l1);
l1.insert(pos, 3, 200);//在pos前增加3个200
PrintList(l1);
vector<int> v{ 201,202,203 };
l1.insert(pos, v.begin(), v.end());//在pos前加入201,202,203
PrintList(l1);
l1.erase(pos);//删除pos(2)
PrintList(l1);
list<int> tmp(l1);//拷贝构造
l1.erase(l1.begin(), l1.end());//删除l1中的数据
PrintList(l1);
PrintList(tmp);
list<int> l2{ 13,24,56,67 };
PrintList(l2);
PrintList(tmp);
l2.swap(tmp);//交换l2与tmp
PrintList(l2);
PrintList(tmp);
cout << l2.size() << endl;
return 0;
}
(6)迭代器失效问题
迭代器失效是指迭代器所指向的节点的无效,即该节点被删除了。因为list底层结构为带有头结点的双向循环链表,因此在进行插入时是不会导致list迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他的迭代器不会受到影响
#include<iostream>
#include<list>
using namespace std;
void PrintList(const list<int>& l1)
{
for (auto x : l1)
{
cout << x << " ";
}
cout << endl;
}
int main()
{
list<int> l1{ 1,2,3,4,5 };
PrintList(l1);
for (auto it = l1.begin(); it != l1.end();)
{
if (*it % 2 == 0)
{
it = l1.erase(it);//删除偶数会导致迭代器失效,所以在下一次使用时,必须先赋值
}
else
{
it++;//不删除的情况下正常+1
}
}
PrintList(l1);
return 0;
}