【C++】STL之list

基本概念

list是一个计算机专业术语,在编程语言中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
void list_test1()
{
	list<int> l1;
	list<int> l2(2, 100);
	list<int> l3(l2);
	int a[] = { 12,34,56,78 };
	
	list<int> l4(a, a + sizeof(a) / sizeof(int));
	vector<char> v(3, 'a');
	list<char> l5(v.begin(), v.end());
	for (auto a : l1)
	{
		cout << a << " ";
	}
	cout << endl;
	for (auto a : l2)
	{
		cout << a << " ";
	}
	cout << endl;
	for (auto a : l3)
	{
		cout << a << " ";
	}
	cout << endl;
	for (auto a : l4)
	{
		cout << a << " ";
	}
	cout << endl;
	for (auto a : l5)
	{
		cout << a << " ";
	}
	cout << endl;
}
输出

100 100
100 100
12 34 56 78
a a a

2.iterator的使用
函数名称功能简述
begin()获取第一个数据位置的iterator
end()获取最后一个数据的下一个位置的iterator
rbegin()获取最后一个数据位置的reverse_iterator
rend()获取第一个数据的前一个位置的reverse_iterator
cbegin()(C++11)获取第一个数据位置的const_iterator
cend()(C++11)获取最后一个数据的下一个位置的const_iterator
crbegin()(C++11)crend()的位置
crend()(C++11)cbegin()的位置
void list_test2()
{
	int a[] = { 12,23,34,45,56,67,78,89,90 };
	list<int> l1(a, a + sizeof(a) / sizeof(int));
	auto it1 = l1.begin();
	while (it1 != l1.end())
	{
		cout << *it1 << " ";
		++it1;
	}
	cout << endl;
	auto it2 = l1.rbegin();
	while (it2 != l1.rend())
	{
		cout << *it2 << " ";
		++it2;
	}
	cout << endl;
	auto it3 = l1.cbegin();
	while (it3 != l1.cend())
	{
		cout << *it3 << " ";
		++it3;
	}
	cout << endl;
	auto it4 = l1.crbegin();
	while (it4 != l1.crend())
	{
		cout << *it4 << " ";
		++it4;
	}
	cout << endl;

}
输出
12 23 34 45 56 67 78 89 90
90 89 78 67 56 45 34 23 12
12 23 34 45 56 67 78 89 90
90 89 78 67 56 45 34 23 12

3.list capacity的函数
函数名称功能简述
bool empty() const判断list是否为空,是返回true,否返回false
size_t size() cosnt返回list中有效数据的个数
void list_test3()
{
	list<int> l1(3, 5);
	bool bl = l1.empty();
	cout << bl << endl;
	size_t sl = l1.size();
	cout << sl << endl;
}
输出
0
3

4.元素访问
函数名称功能简述
reference front()返回list的第一个节点中值的引用
const_reference front() const返回list的第一个节点中值的const引用
reference back()返回list的最后一个节点中值的引用
const_reference back() const返回list的最后一个节点中值的const引用
void list_test4()
{
	int a[] = { 1,2,4,5,67,8 };
	list<int> l1(a, a + sizeof(a) / sizeof(int));
	for (auto a : l1)
	{
		cout << a << " ";
	}
	cout << endl;
	l1.front() = 11;
	l1.back() = 88;
	for (auto a : l1)
	{
		cout << a << " ";
	}
	cout << endl;
	const list<int> l2(a, a + sizeof(a) / sizeof(int));
	const int& cfl2 = l2.front();
	const int& cbl2 = l2.back();
	//l2.front() = 11;
	//l2.back() = 11;//注释掉的原因,见下图
	cout << cfl2 << endl;
	cout << cbl2 << endl;
}
输出
1 2 4 5 67 8
11 2 4 5 67 88
1
8

在这里插入图片描述

5.修改操作
函数名称功能简述
void push_front(const value_type& val)list头插val
void pop_front()list头删
void push_back(const_value_type& val)list尾插val
void pop_back()list尾删
template <class… Args> void emplace_front(Args&&…args)(C++11list第一个元素前根据参数直接构造元素
template <class… Args> void emplace_back(Args&&…args)(C++11list最后一个元素后根据参数直接构造元素
template <class… Args> iterator emplace (const_iterator position, Args&&… args)(C++11listposition位置根据参数直接构造元素
iterator insert (const_iterator position, const value_type& val)listposition位置插入val
void insert(iterator position,size_type n,const value_type& val)listposition位置插入nval
template iterator insert (const_iterator position, InputIterator first, InputIterator last)listposition位置插入[first,last) (范围:左闭右开) 中的元素
iterator erase(iterator position)删除listposition位置的元素
iterator erase(iterator first,iterator last)删除list中[first,last)(范围:左闭右开) 中的元素
void swap(list& x)交换两个list中的元素
void resize(size_type n,value_type val =value_type())list中有效元素改变至n个,多出的元素用val填充,在int中默认val=0,如果是自定义类型,就调用缺省构造函数
void clear()清空list中的有效元素
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{}
	Date(const Date& d)
		:_year(d._year)
		, _month(d._month)
		, _day(d._day)
	{}
	static void Print(const Date& d)
	{
		cout << d._year << "-" << d._month << "-" << d._day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
void list_test5()
{
	//push_back()、push_front()、pop_back()、pop_front()
	list<int> l1(3, 5);
	l1.push_back(1);
	l1.push_front(4);
	Print_List(l1);
	l1.pop_back();
	l1.pop_front();
	Print_List(l1);
	//emplace_front()、emplace_back()、emplace
	list<Date> l2;
	Date d;
	l2.push_back(d);
	l2.emplace_back(2019, 11, 14);
	l2.emplace_front(2018, 11, 14);
	auto it2 = l2.begin();
	while (it2 != l2.end())
	{
		Date::Print(*it2);
		++it2;
	}
	//insert、erase
	int a[] = { 1,2,3,4 };
	list<int> l3(a,a+sizeof(a)/sizeof(int));
	auto it3 = l3.begin();
	cout << *it3 << endl;
	auto pos = find(l3.begin(), l3.end(), 2);
	l3.insert(pos, 22);
	l3.insert(it3, 11);
	cout << *it3 << endl;//并没有发生迭代器失效
	while (it3 != l3.end())
	{
		cout << *it3 << " ";
		++it3;
	}
	cout << endl;
	Print_List(l3);
	int b[] = { 12,23,34,45 };
	list<int> l4(2, 3);
	Print_List(l4);
	l4.insert(l4.begin(), b, b + sizeof(b) / sizeof(int));
	Print_List(l4);
	l4.erase(l4.begin());
	Print_List(l4);
	l4.erase(l4.begin(), l4.end());
	Print_List(l4);
	//swap、resize、clear
	list<int> l5(3, 3);
	list<int> l6(3, 6);
	cout << "l5:";
	Print_List(l5);
	cout << "l6:";
	Print_List(l6);
	l5.swap(l6);
	cout << "swap()之后" << endl;
	cout << "l5:";
	Print_List(l5);
	cout << "l6:";
	Print_List(l6);
	l5.resize(10,10);
	Print_List(l5);
	l6.resize(2, 2);
	Print_List(l6);
	l6.clear();
	Print_List(l6);
}
输出
4 5 5 5 1
5 5 5
2018-11-14
1900-1-1
2019-11-14
1
1
1 22 2 3 4
11 1 22 2 3 4
3 3
12 23 34 45 3 3
23 34 45 3 3

l5:3 3 3
l6:6 6 6
swap()之后
l5:6 6 6
l6:3 3 3
6 6 6 10 10 10 10 10 10 10
3 3


迭代器失效

由于list底层结构是带头结点的双向循环链表,所以list
insert并不会导致迭代器失效,只有在erase时才会失效
erase()函数执行后,iterator所指向的节点已被删除,
因此iterator无效,所以无法通过++来找到下一个节点,

所以相比于vector而言,list中的迭代器失效比较简单,因为list只有野指针iterator所指向的位置已经被释放)这一种情况
解决方法:重新获取一下
void list_test6()
{
	int a[] = { 1,2,3,4,5,6,7 };
	list<int> l1(a, a + sizeof(a) / sizeof(int));
	Print_List(l1);
	auto it1 = l1.begin();
	//迭代器失效场景
	/*while (it1 != l1.end())
	{
		l1.erase(it1);
		++it1;
	}*/
	//解决方法:重新获取一下
	while (it1 != l1.end())
	{
		l1.erase(it1++);
		//++it1;
	}
	Print_List(l1);
	list<int> l2(a, a + sizeof(a) / sizeof(int));
	Print_List(l2);
	auto it2 = l2.begin();
	while (it2 != l2.end())
	{
		if (*it2 % 2 != 0)
		{
			l2.erase(it2++);
		}
		else
			//++it2;
			++it2;
	}
	Print_List(l2);
}
输出
1 2 3 4 5 6 7

1 2 3 4 5 6 7
2 4 6
vectorlist的对比
vectorlist
底层结构动态顺序表,连续的一段空间带头结点的双向链表
随机访问支持随机访问,时间复杂度为O(1)不支持随机访问,访问任意元素,时间复杂度为O(N)
插入和删除任意位置插入和删除效率低,需要移动元素,时间复杂度O(N),插入时可能会增容,增容:开辟新空间,拷贝元素,释放旧空间,导致效率低下任意位置的插入删除效率高,不需要移动元素,时间复杂度为O(1)
空间利用率底层是一片连续的空间,不容易造成内存碎片化,空间利用率高,缓存利用率高底层结点动态开辟,小结点容易造成内存碎片化,空间利用率低,缓存利用率低
迭代器只是一种简单的指针对简单指针的封装
迭代器失效插入,删除时均会导致迭代器失效,只有删除时才会导致迭代器失效
使用场景需要高效率存储,支持随机访问,较少的插入、删除操作大量的插入、删除,不是很需要随机访问
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值