1.前言

我们这里的List(链表)是带头双向循环链表,这一点在下一篇文章的对list的模拟实现是至关重要的,本篇文章主要讲解的是c++自带的list的相关接口!

2.接口及其应用

2.1 遍历数据(迭代器和范围for)

遍历list的方法和以往我们遍历vector,string的方式类似,一种是用迭代器,另外一种则是利用范围for,二者本质是一样的

相关代码如下:

void list_test1()
{
	list<int> lt1;
	lt1.push_back(1);
	lt1.push_back(2);
	lt1.push_back(3);
	lt1.push_back(4);
	lt1.push_back(5);
	lt1.push_back(6);

	list<int> lt2 = { 6,5,4,3,2,1 };

	//两种遍历的方式
	//法一)直接用迭代器,相当于指针
	list<int>::iterator it1 = lt1.begin();
	while (it1 != lt1.end())
	{
		cout << *it1 << " ";
		++it1;
	}
	cout << endl;

	//法二)用范围for,但是本质还是迭代器,能用迭代器就能用范围for
	for (const auto e : lt2)
	{
		cout << e << " ";
	}
	cout << endl;
}

2.2 替换数据(assign函数)

 简单来说,就是assign我们要传两个参数,lt.assign(x,y),结果就是输出x个y!

代码如下:

void list_test2()     //验证assign的作用
{
	list<int> lt1 = { 1,2,3,4,5,6,7,8,9 };
	list<int>::iterator it = lt1.begin();
	while (it != lt1.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
	lt1.assign(3, 2);
	for (auto e : lt1)
	{
		cout << e << " ";
	}
	cout << endl;
	lt1.assign(10, 1);
	for (auto e : lt1)
	{
		cout << e << " ";
	}
}

运行结果:

2.3 插入数据(push_back\emplace_back)

插入数据(以尾插为例)可以用push_back函数以及emplace_back函数 

 

下面谈一下二者的异同点:

同:1.两者都用于在容器的末尾添加元素,扩展容器的大小。 

       2.它们都可以用于支持动态扩展的容器,如 std::vectorstd::liststd::deque 等。

异:1.push_back接受一个已经构造好的对象作为参数,并将其复制或移动到中。需要先构造一个            对象,然后将其复制或移动到容器中。如果对象的构造和复制/移动操作代价较高,性能受              到影响。

      2.emplace_back接受构造参数,并在容器的末尾原地构造对象,避免了额外的复制或移动操              作。 直接在容器分配的内存中构造对象,减少了不必要的复制或移动操作,通常性能更高。

代码如下:

struct A
{
	A(int a1 = 1, int a2 = 2,int a3=3)
		:_a1(a1)
		, _a2(a2)
		,_a3(a3)
	{}
	int _a1;
	int _a2;
	int _a3;
};
ostream& operator<<(ostream& out,A& lt)     //你的范围for每个元素的类型是A, 所以要换成A&, 然后函数里面打印的时候,需要指定A里面的成员变量。
{
	out << lt._a1<<lt._a2<<lt._a3;
	return out;
}
void list_test3()    //插入数据的方法
{
	//法一)直接利用库函数
	list<int> lt;
	// 只能插入int
	lt.push_back(1);
	lt.push_back(2);
	// 插入int
	lt.emplace_back(3);
	lt.emplace_back(4);
	
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
	//其余插入数据的方法:利用构造
	list<A> lt2;
	A aa1(2, 2, 1);
	lt2.push_back(aa1);
	for (auto e1 : lt2)
	{
		cout << e1 << " ";
	}
	cout << endl;
	lt2.push_back(A(2, 6, 5));
	lt2.push_back({ 2,9,1 });

	lt2.emplace_back(aa1);
	lt2.emplace_back(A(2, 2, 5));
	//更高效
	lt2.emplace_back(2, 2, 1);
	for (auto e1 : lt2)
    {
	    cout << e1 << " ";
    }
    cout << endl;
}

 运行结果:

 

 2.4 删除数据(remove函数)

 简单来说,就是移除指定数字,即lt.remove(x),就是移除lt中所有值为x的数

代码如下:

void list_test4()      //remove
{
	list<int> lt = { 1,2,3,5,5,5,7,8,5 };
	list<int>::iterator it = lt.begin();
	while (it != lt.end())
	{
		cout << *it << " ";        //1 2 3 5 5 5 7 8 5
		++it;
	}
	cout << endl;
	lt.remove(100);     //没有要移动的数字就不动了
	for (auto ch : lt)
	{
		cout << ch << " ";        //1 2 3 5 5 5 7 8 5
	}
	cout << endl;
	lt.remove(5);    //删除所有的5
	for (auto e : lt)
	{
		cout << e << " ";        //1 2 3 7 8
	}
	cout << endl;
	lt.remove(3);
	for (auto e1 : lt)
	{
		cout << e1 << " ";      //1 2 7 8
	}
}

2.5 对数据的排序

 

说明:sort()函数是默认排升序的,如果想排降序,则需要使用greater

 

代码如下:

void list_test5()     //排序
{
	list<int> lt = { 10,6,2,8,3,1,5,95 };
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
	// 不支持
 // sort(lt1.begin(), lt1.end())
	lt.sort();           //默认排升序
	for (auto e1 : lt)
	{
		cout << e1 << " ";
	}
	cout << endl;

	//排降序
	//法一)
	
	//greater<int> gt;
	//lt.sort(gt);
	
	//法二)对上述进行简化
	lt.sort(greater<int>());
	for (auto e1 : lt)
	{
		cout << e1 << " ";
	}
	cout << endl;
}

 运行结果:

2.5 数据去重(unique函数)

有一点值得注意的是,其与remove(x)函数不同,remove函数是移除所有值为x的数,没有什么要求,但是unique函数,不会将所有值为x的数都移除走,实现的功能是去重,必须是当有n个x相连时,才可以把后面n-1个x移除掉,而且必须是在有序的情况下,其工作原理可以类比数据结构的双指针法

代码如下:

void list_test6()    //unique,必须要在有序的情况下使用,升降序都行
{
	list<int> lt = { 10,2,5,3,2,6,2,2,1,3 };
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
	lt.sort(greater<int>());
	for (auto e2 : lt)
	{
		cout << e2 << " ";
	}
	cout << endl;
	lt.unique();
	for (auto e3 : lt)
	{
		cout << e3 << " ";
	}
	cout << endl;
}

运行结果:

2.6  数据移动(splice函数)

 

 说明:splice函数有以下三种用法:

用法一)将一个列表的所有元素移动到另一个列表的指定位置

解释:将 other 中的所有元素移动到当前列表的 pos 指向的位置之前

示例:

 

用法二)将一个列表中的单个元素移动到另一个列表的指定位置

 

解释:将 other 中由 it 指向的单个元素移动到当前列表的 pos 指向的位置之前

示例:

 用法三)将一个列表中指定范围的元素移动到另一个列表的指定位置

 解释:将 other 中从 firstlast(不包括 last)范围内的元素移动到当前列表的 pos 指向的位置之前

示例:

 代码如下(补充)

void list_test7()
{
	list<int> lt = { 1,3,5,7,9 };
	list<int> lt2 = { 2,4,6,8,10 };
	cout << "lt:";
	for (auto e : lt)
	{
		cout << e << " ";           //lt:1 3 5 7 9
	}
	cout << endl;
	cout << "lt2:";
	for (auto e : lt2)
	{
		cout << e << " ";           //lt:2 4 6 8 10
	}
	cout << endl;
	// 1移动到尾部
	lt.splice(lt.end(), lt, lt.begin());
	for (auto e3 : lt)
	{
		cout << e3 << " ";         //3 5 7 9 1
	}
	cout << endl;
	//将 lt2 中的所有元素移动到当前列表的 lt 指向的位置之前
	lt.splice(lt.begin(), lt2);
	for (auto e3 : lt)
	{
		cout << e3 << " ";        //2 4 6 8 10 3 5 7 9 1
	}
	cout << endl;
}

最后,附上总的代码

 

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

void list_test1()
{
	list<int> lt1;
	lt1.push_back(1);
	lt1.push_back(2);
	lt1.push_back(3);
	lt1.push_back(4);
	lt1.push_back(5);
	lt1.push_back(6);

	list<int> lt2 = { 6,5,4,3,2,1 };

	//两种遍历的方式
	//法一)直接用迭代器,相当于指针
	list<int>::iterator it1 = lt1.begin();
	while (it1 != lt1.end())
	{
		cout << *it1 << " ";
		++it1;
	}
	cout << endl;

	//法二)用范围for,但是本质还是迭代器,能用迭代器就能用范围for
	for (const auto e : lt2)
	{
		cout << e << " ";
	}
	cout << endl;
}

void list_test2()     //验证assign的作用
{
	list<int> lt1 = { 1,2,3,4,5,6,7,8,9 };
	list<int>::iterator it = lt1.begin();
	while (it != lt1.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
	lt1.assign(3, 2);
	for (auto e : lt1)
	{
		cout << e << " ";
	}
	cout << endl;
	lt1.assign(10, 1);
	for (auto e : lt1)
	{
		cout << e << " ";
	}
}
struct A
{
	A(int a1 = 1, int a2 = 2,int a3=3)
		:_a1(a1)
		, _a2(a2)
		,_a3(a3)
	{}
	int _a1;
	int _a2;
	int _a3;
};
ostream& operator<<(ostream& out,A& lt)     //你的范围for每个元素的类型是A, 所以要换成A&, 然后函数里面打印的时候,需要指定A里面的成员变量。
{
	out << lt._a1<<lt._a2<<lt._a3;
	return out;
}
void list_test3()    //插入数据的方法
{
	//法一)直接利用库函数
	list<int> lt;
	// 只能插入int
	lt.push_back(1);
	lt.push_back(2);
	// 插入int
	lt.emplace_back(3);
	lt.emplace_back(4);
	
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
	//其余插入数据的方法:利用构造
	list<A> lt2;
	A aa1(2, 2, 1);
	lt2.push_back(aa1);
	for (auto e1 : lt2)
	{
		cout << e1 << " ";
	}
	cout << endl;
	lt2.push_back(A(2, 6, 5));
	lt2.push_back({ 2,9,1 });

	lt2.emplace_back(aa1);
	lt2.emplace_back(A(2, 2, 5));
	//更高效
	lt2.emplace_back(2, 2, 1);
	for (auto e1 : lt2)
    {
	    cout << e1 << " ";
    }
    cout << endl;
}
void list_test4()      //remove
{
	list<int> lt = { 1,2,3,5,5,5,7,8,5 };
	list<int>::iterator it = lt.begin();
	while (it != lt.end())
	{
		cout << *it << " ";        //1 2 3 5 5 5 7 8 5
		++it;
	}
	cout << endl;
	lt.remove(100);     //没有要移动的数字就不动了
	for (auto ch : lt)
	{
		cout << ch << " ";        //1 2 3 5 5 5 7 8 5
	}
	cout << endl;
	lt.remove(5);    //删除所有的5
	for (auto e : lt)
	{
		cout << e << " ";        //1 2 3 7 8
	}
	cout << endl;
	lt.remove(3);
	for (auto e1 : lt)
	{
		cout << e1 << " ";      //1 2 7 8
	}
}
void list_test5()     //排序
{
	list<int> lt = { 10,6,2,8,3,1,5,95 };
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
	// 不支持
 // sort(lt1.begin(), lt1.end())
	lt.sort();           //默认排升序
	for (auto e1 : lt)
	{
		cout << e1 << " ";
	}
	cout << endl;

	//排降序
	//法一)
	
	//greater<int> gt;
	//lt.sort(gt);
	
	//法二)对上述进行简化
	lt.sort(greater<int>());
	for (auto e1 : lt)
	{
		cout << e1 << " ";
	}
	cout << endl;
}
void list_test6()    //unique,必须要在有序的情况下使用,升降序都行
{
	list<int> lt = { 10,2,5,3,2,6,2,2,1,3 };
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
	lt.sort(greater<int>());
	for (auto e2 : lt)
	{
		cout << e2 << " ";
	}
	cout << endl;
	lt.unique();
	for (auto e3 : lt)
	{
		cout << e3 << " ";
	}
	cout << endl;
}
void list_test7()
{
	list<int> lt = { 1,3,5,7,9 };
	list<int> lt2 = { 2,4,6,8,10 };
	cout << "lt:";
	for (auto e : lt)
	{
		cout << e << " ";           //lt:1 3 5 7 9
	}
	cout << endl;
	cout << "lt2:";
	for (auto e : lt2)
	{
		cout << e << " ";           //lt:2 4 6 8 10
	}
	cout << endl;
	// 1移动到尾部
	lt.splice(lt.end(), lt, lt.begin());
	for (auto e3 : lt)
	{
		cout << e3 << " ";         //3 5 7 9 1
	}
	cout << endl;
	//将 lt2 中的所有元素移动到当前列表的 lt 指向的位置之前
	lt.splice(lt.begin(), lt2);
	for (auto e3 : lt)
	{
		cout << e3 << " ";        //2 4 6 8 10 3 5 7 9 1
	}
	cout << endl;
}
int main()
{
	//list_test1();
	//list_test2();
      //list_test3();
	//list_test4();
	//list_test5();
	//list_test6();
	list_test7();
	return 0;
}

本文到此结束,如有不恰当指出,欢迎指正!下一篇我们将讲解如何自己实现list类! 

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐