C++学习笔记(十六)——list

list的介绍

list常见接口的介绍

list的构造函数

list中迭代器

list的迭代器遍历

list的增删查改

list的大小和头尾元素读取

list的操作函数

list迭代器失效


list的介绍

list本质是一个带头的双向循环链表

  • list是一种可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
  • list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立结点当中,在结点中通过指针指向其前一个元素和后一个元素。
  • list与forward_list非常相似,最主要的不同在于forward_list是单链表,只能进行单方向迭代。
  • 与其他容器相比,list通常在任意位置进行插入、删除元素的执行效率更高。
  • list和forward_list最大的缺陷是不支持在任意位置的随机访问,其次,list还需要一些额外的空间,以保存每个结点之间的关联信息(对于存储的类型较小元素来说这可能是一个重要的因素)。

list常见接口的介绍

list的构造函数

1.无参构造:list()

list<int> lt1;

 2.用n个值为val的元素构造:list(size_type n,const value_type& val=value_type())

list<int> lt2(10,2);

 3.拷贝构造:list(const list& lt)

list<int> lt3(lt2);

4. 用一段区间的元素构造list:list(Inputlterator first,Inputlterator last)

string s("hello world");
list<char> lt4(s.begin(),s.end());

实例演示

void PrintList(const list<int>& lt)
{
	list<int>::const_iterator it = lt.begin();
	while (it != lt.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
}
void test4()
{
	list<int> lt1;
	list<int> lt2(5, 2);
	list<int> lt3(lt2);
	list<int> lt4(lt2.begin(), lt2.end());
	cout << "lt1:";
	PrintList(lt1);
	cout << "It2:";
	PrintList(lt2);
	cout << "It3:";
	PrintList(lt3);
	cout << "It4:";
	PrintList(lt4);

}

代码运行结果如下:

list中迭代器

1.begin和end

 通过begin函数可以得到容器中第一个元素的正向迭代器,通过end函数可以得到容器中最后一个元素的后一个位置的正向迭代器。

void test12()
{
	list<int> lt(10, 2);
	list<int>::iterator it = lt.begin();
	while (it != lt.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
}

运行结果: 

 

2.rbegin和rend

 通过rbegin函数可以得到容器中最后一个元素的反向迭代器,通过rend函数可以得到容器中第一个元素的前一个位置的反向迭代器。

void test13()
{
	list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);
	list<int>::reverse_iterator it = lt.rbegin();
	while (it != lt.rend())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;

}

运行结果

list的迭代器遍历

void TestList2()
{
	list<int>lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);

	lt.push_front(0);
	lt.push_front(-1);
	lt.push_front(-2);

	list<int>::iterator it = lt.begin();
	while (it != lt.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;

	list<int>::reverse_iterator rit = lt.rbegin();
	while (rit != lt.rend())
	{
		cout << *rit << " ";
		++rit;
	}
	cout << endl;
}

运行结果:

list的增删查改

1.push_front和pop_front

 push_front函数用于头插一个数据,pop_front函数用于头删一个数据。

void test5()
{
	list<int> lt;
	lt.push_front(1);
	lt.push_front(2);
	lt.push_front(3);
	lt.push_front(4);
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;

	lt.pop_front();
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
	
}

演示:

2.push_back和pop_back

push_back函数用于尾插一个数据,pop_back函数用于尾删一个数据。

void test6()
{
	list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
	lt.pop_back();
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
	
}

演示:

3.insert

 list当中的insert函数支持三种插入方式:

  • 在指定迭代器位置插入一个数。
  • 在指定迭代器位置插入n个值为val的数。
  • 在指定迭代器位置插入一段迭代器区间(左闭右开)。
void test7()
{
	list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	//1.在指定迭代器位置插入一个数
	list<int>::iterator pos = find(lt.begin(), lt.end(), 2);
	lt.insert(pos, 9);
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
	//2.在指定迭代器位置插入n个值为val的数
	pos = find(lt.begin(), lt.end(), 3);
	lt.insert(pos, 2, 8);
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
	
}

演示:

4.erase

list当中的erase函数支持两种删除方式:

1.删除指定迭代器位置的元素。

2.删除指定迭代器区间的所有元素

void test8()
{
	list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);
	lt.push_back(5);
	//删除指定迭代器位置的元素
	list<int>::iterator pos = find(lt.begin(), lt.end(), 2);
	lt.erase(pos);
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
	//删除指定迭代器区间的所有元素
	pos = find(lt.begin(), lt.end(), 4);
	lt.erase(pos, lt.end());
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
}

演示

 

list的大小和头尾元素读取

1.size

size函数用于获取当前容器当中得元素个数.

void test11()
{
	list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);
	cout << lt.size() << endl;//4

}

2.resize

 resize的两种情况:

  • 当所给值大于当前的size时,将size扩大到该值,扩大的数据为第二个所给值,若未给出,则默认为容器所存储类型的默认构造函数所构造出来的值。
  • 当所给值小于当前的size时,将size缩小到该值。
void test17()
{
	list<int> lt(5, 3);
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
	lt.resize(7, 6);
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
	lt.resize(2);
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
}

 运行结果:

3.empty

empty函数用于判断当前容器是否为空。

void test16()
{
	list<int> lt;
	cout << lt.empty() << endl;//1
}

4.clear

 clear函数用于清空容器,清空后容器的size为0。

void test15()
{
	list<int> lt(5, 2);
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
	cout << lt.size() << endl;
	lt.clear();
	cout << lt.size() << endl;
}

运行结果:

 

5.front和back

  front函数用于获取list容器当中的第一个元素,back函数用于获取list容器当中的最后一个元素。

void test14()
{
	list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	cout << lt.front() << endl;
	cout << lt.back() << endl;
}

运行结果: 

 

list的操作函数

1.sort

sort函数可以将容器当中的数据默认排为升序。

void test19()
{
	list<int> lt;
	lt.push_back(2);
	lt.push_back(5);
	lt.push_back(8);
	lt.push_back(10);
	lt.push_back(11);
	lt.push_back(7);
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
	lt.sort();
	for (auto e : lt)
	{
		cout << e << " ";
	}
}

运行结果

 

2.splice

splice函数用于两个list容器之间的拼接,其有三种拼接方式:

1.将整个容器拼接到另一个容器的指定迭代器位置。

2.将容器当中的某一个数据拼接到另一个容器的指定迭代器位置。

3.将容器指定迭代器区间的数据拼接到另一个容器的指定迭代器位置。

#include <iostream>
#include <list>
using namespace std;

int main()
{
	list<int> lt1(4, 2);
	list<int> lt2(4, 6);
	lt1.splice(lt1.begin(), lt2); //将容器lt2拼接到容器lt1的开头
	for (auto e : lt1)
	{
		cout << e << " ";
	}
	cout << endl; //6 6 6 6 2 2 2 2 

	list<int> lt3(4, 2);
	list<int> lt4(4, 6);
	lt3.splice(lt3.begin(), lt4, lt4.begin()); //将容器lt4的第一个数据拼接到容器lt3的开头
	for (auto e : lt3)
	{
		cout << e << " ";
	}
	cout << endl; //6 2 2 2 2 

	list<int> lt5(4, 2);
	list<int> lt6(4, 6);
	lt5.splice(lt5.begin(), lt6, lt6.begin(), lt6.end()); //将容器lt6的指定迭代器区间内的数据拼接到容器lt5的开头
	for (auto e : lt5)
	{
		cout << e << " ";
	}
	cout << endl; //6 6 6 6 2 2 2 2
	return 0;
}

注意: 容器当中被拼接到另一个容器的数据在原容器当中就不存在了。(实际上就是将链表当中的指定结点拼接到了另一个容器当中) 

3.remove

remove函数用于删除容器当中特定值的元素。

#include <iostream>
#include <list>
using namespace std;

int main()
{
	list<int> lt;
	lt.push_back(1);
	lt.push_back(4);
	lt.push_back(3);
	lt.push_back(3);
	lt.push_back(2);
	lt.push_back(2);
	lt.push_back(3);
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl; //1 4 3 3 2 2 3
	lt.remove(3); //删除容器当中值为3的元素
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl; //1 4 2 2
	return 0;
}

4.reverse

 reverse函数用于将容器当中元素的位置进行逆置。

void test21()
{
	list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.reverse();
	for (auto e : lt)
	{
		cout << e << " ";
	}
	
}

运行结果:

  

5.assign

assign函数用于将新内容分配给容器,替换其当前内容,新内容的赋予方式有两种:

1.将n个值为val的数据分配给容器

2.将所给迭代器区间当中的内容分配给容器

void test20()
{
	list<char> lt(3, 'a');
	lt.assign(3, 'b');
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
	string s("hello world");
	lt.assign(s.begin(), s.end());
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
}

运行结果:

  

6.swap

void test18()
{
	list<int> lt1(4, 2);
	list<int> lt2(4, 6);
	lt1.swap(lt2);
	for (auto e : lt1)
	{
		cout << e << " ";
	}
	cout << endl;
	for (auto e : lt2)
	{
		cout << e << " ";
	}
	cout << endl;
}

运行结果

 

list迭代器失效

迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list种进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。

两种情况测试

1.插入

void test9()
{
	int arr[] = { 1,2,3,4,5 };
	list<int> lt(arr, arr + sizeof(arr) / sizeof(arr[0]));
	list<int>::iterator it = lt.begin();
	lt.insert(it, 3);
	for (auto e : lt)
	{
		cout << e << " ";
	}
}

代码运行结果:

2.删除

void test10()
{
	int arr[] = { 1,2,3,4,5 };
	list<int> lt(arr, arr + sizeof(arr) / sizeof(arr[0]));
	list<int>::iterator it = lt.begin();
	while (it != lt.end())
	{
		lt.erase(it);
		++it;
	}
}

代码运行结果: 

总结: 插入数据不会导致迭代器失效,删除数据会导致迭代器失效。相比vector容器,vector容器插入数据是会导致迭代器失效,因为vector涉及增容问题,而list却不存在增容问题,所以迭代器指向的位置是有效的。删除数据会导致迭代器指向的位置是无效的,所以迭代器会失效。

修改后的代码如下:

void test10()
{
	int arr[] = { 1,2,3,4,5 };
	list<int> lt(arr, arr + sizeof(arr) / sizeof(arr[0]));
	list<int>::iterator it = lt.begin();
	while (it != lt.end())
	{
		it = lt.erase(it);
	}
	
}
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

接受平凡 努力出众

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值