全面理解C++STL中的list容器(附实战练习——学生成绩管理系统)

Posted Domo泷

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了全面理解C++STL中的list容器(附实战练习——学生成绩管理系统)相关的知识,希望对你有一定的参考价值。

1.list容器基本概念

(1)list容器实际上就是一个链表,不同于vector容器,list容器是通过指针将数据链式储存起来;

(2)链表是由一系列结点组成的,每一个结点由储存数据的数据域和储存下一个数据的地址的指针域组成;

链表的知识在之前的文章中**线性表的链式存储结构 ( 链表 ).**

list容器中的链表是一个双向循环链表,如下图所示;

(1)list的优缺点

1 . 采用动态存储分配,不会造成内存浪费和溢出;
2 . 链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素。

1 .list链表的访问不支持随机访问,只能使用迭代器访问,操作较复杂
2 . 链表灵活,但是空间(指针域)和时间(遍历)额外耗费较大,遍历速度没有数组快,且占用空间比数组大。
3 . list有一个重要的性质,插入操作和删除操作都不会造成原有list迭代器的失效,这在vector是不成立的。

好了,理论知识就到这里,我们主要靠实战举例理解

2.创建list容器

构造函数原型:(和vector基本相同)

list<T> lst; //list默认构造形式:
list(begin,end); //构造函数将[begin, end)区间中的元素拷贝给本身。
list(n,e); //构造函数将n个e赋给给本身。
list(const list &lst); //拷贝构造函数

示例

#include<iostream>
using namespace std;
#include <list>//C++ 中的容器使用之前都得包含相应头文件

void showList01(const list<int>& L) //唯一一种方式打印list容器中的数据,因为list容器只能通过迭代器访问


	for (list<int>::const_iterator p = L.begin(); p != L.end(); p++) 
		cout << *p << " ";
	
	cout << endl;

void testit()

	list<int>L1;
	for (int i = 3; i < 50; i += 10)
	
		L1.push_back(i);
	
	

	showList01(L1);

	list<int>L2(L1.begin(), L1.end());
	showList01(L2);

	list<int>L3(L2);
	showList01(L3);

	list<int>L4(10, 666);
	showList01(L4);


int main() 

	testit();

	system("pause");

	return 0;

运行结果

3.list容器赋值和交换

接口函数原型(和vector基本相同)

assign(begin, end); //将[begin, end)区间中的数据赋值给容器。
assign(n, t); //将n个t拷贝赋值给本身。
list& operator=(const list &lst); //重载等号操作符
swap(lst); //将lst与本身的元素互换。

示例

#include<iostream>
using namespace std;
#include <list>//C++ 中的容器使用之前都得包含相应头文件

void showList01(const list<int>& L) //唯一一种方式打印list容器中的数据,因为list容器只能通过迭代器访问


	for (list<int>::const_iterator p = L.begin(); p != L.end(); p++) 
		cout << *p << " ";
	
	cout << endl;


//赋值和交换
void testit01()

	list<int>L1;
	for (int i = 3; i < 50; i += 10)
	
		L1.push_back(i);
	
	showList01(L1);

	//赋值
	list<int>L2;
	L2 = L1;
	showList01(L2);

	list<int>L3;
	L3.assign(L2.begin(), L2.end());
	showList01(L3);

	list<int>L4;
	L4.assign(10, 33);
	showList01(L4);



//交换
void testit02()


	list<int>L1;
	for (int i = 3; i < 50; i += 10)
	
		L1.push_back(i);
	
	list<int>L2;
	L2.assign(10, 66);

	cout << "交换前: " << endl;
	showList01(L1);
	showList01(L2);

	cout << endl;

	L1.swap(L2);

	cout << "交换后: " << endl;
	showList01(L1);
	showList01(L2);



int main() 

	testit01();

	cout << "***********下一个测试案例**********" << endl;

	testit02();

	system("pause");

	return 0;

运行结果

4.list大小操作

接口函数原型(和vector基本相同)

size(); //返回容器中元素的个数

empty(); //判断容器是否为空

resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。//如果容器变短,则末尾超出容器长度的元素被删除。

resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。若容器变短,则删除多余的部分

示例

#include<iostream>
using namespace std;
#include <list>//C++ 中的容器使用之前都得包含相应头文件

void showList01(const list<int>& L) //唯一一种方式打印list容器中的数据,因为list容器只能通过迭代器访问


	for (list<int>::const_iterator p = L.begin(); p != L.end(); p++) 
		cout << *p << " ";
	
	cout << endl;


//大小操作
void testit01()

	list<int>L1;
	for (int i = 3; i < 50; i += 10)
	
		L1.push_back(i);
	
	showList01(L1);

	if (L1.empty())
	
		cout << "L1为空" << endl;
	
	else
	
		cout << "L1不为空" << endl;
		cout << "L1的大小为: " << L1.size() << endl;
	

	//重新指定大小
	L1.resize(10);
	showList01(L1);

	L1.resize(2);
	showList01(L1);


int main() 

	testit01();

	system("pause");

	return 0;


运行结果

5.list插入和删除

接口函数原型.(和vector有区别点)

push_back(elem);//在容器尾部加入一个元素
pop_back();//删除容器中最后一个元素
push_front(elem);//在容器开头插入一个元素
pop_front();//从容器开头移除第一个元素
insert(pos,elem);//在pos位置插elem元素的拷贝,返回新数据的位置。
//pos为迭代器位置
insert(pos,n,elem);//在pos位置插入n个elem数据,无返回值。
//pos为迭代器位置
insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值。
//pos为迭代器位置
clear();//移除容器的所有数据
erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置。
//beg,end为迭代器,也可通过迭代器++改变区间
erase(pos);//删除pos位置的数据,返回下一个数据的位置。
remove(elem);//删除容器中所有与elem值匹配的元素。

示例

#include<iostream>
using namespace std;
#include <list>//C++ 中的容器使用之前都得包含相应头文件

void showList01(const list<int>& L) //唯一一种方式打印list容器中的数据,因为list容器只能通过迭代器访问


	for (list<int>::const_iterator p = L.begin(); p != L.end(); p++) 
		cout << *p << " ";
	
	cout << endl;



//插入和删除
void testit01()

	list<int> L;
	//尾插fa
	L.push_back(11);
	L.push_back(22);
	L.push_back(33);
	//头插af
	L.push_front(150);
	L.push_front(250);
	L.push_front(350);

	showList01(L);

	//尾删fa
	L.pop_back();
	showList01(L);

	//头删fa
	L.pop_front();
	showList01(L);

	//插入fa
	list<int>::iterator p = L.begin();
	L.insert(++p, 888);
	showList01(L);

	//删除af
	p = L.begin();
	L.erase(++p);
	showList01(L);

	//移除fa
	L.push_back(9999);
	L.push_back(9999);
	L.push_back(999);
	showList01(L);
	L.remove(9999);
	showList01(L);

	//清空fa
	L.clear();
	showList01(L);


int main() 

	testit01();

	system("pause");

	return 0;


运行结果

6.list数据存取

接口函数原型:

front()//返回第一个数据
back()//返回第二个数据
//只能通过迭代器访问

示例

#include<iostream>
using namespace std;
#include <list>//C++ 中的容器使用之前都得包含相应头文件

//数据存取
void testit01()

	list<int>L1;
	for (int i = 3; i < 50; i += 10)
	
		L1.push_back(i);
	

	//list不支持at访问数据和[]方式访问数据
	//只能通过迭代器访问
	cout << "第一个元素为: " << L1.front() << endl;
	cout << "最后一个元素为: " << L1.back() << endl;

	//list容器的迭代器是双向迭代器,不支持随机访问

	list<int>::iterator it = L1.begin();

	//it = it + 1;//错误,不可以跳跃访问,即使是+1

	it++;
	cout << "第二个元素为: " << *it << endl;
	it++;
	cout << "第三个元素为: " << *it << endl;


int main() 

	testit01();

	system("pause");

	return 0;



7.list反转和排序

接口函数原型

reverse(); //反转链表
sort(); //链表排序
//两者都不是STL中的算法函数,而是list容器中自带的接口函数,用法也并不相同

示例

#include<iostream>
using namespace std;
#include <list>//C++ 中的容器使用之前都得包含相应头文件

void showList01(const list<int>& L) //唯一一种方式打印list容器中的数据,因为list容器只能通过迭代器访问


	for (list<int>::const_iterator p = L.begin(); p != L.end(); p++) 
		cout << *p << " ";
	
	cout << endl;



bool My_sortway(int a, int b)

	return a > b;


//反转和排序
void test01()

	list<int> L;
	L.push_back(99);
	L.push_back(33);
	L.push_back(22);
	L.push_back(77);
	showList01(L);

	//反转容器的元素
	L.reverse();
	cout << "反转后 :";
	showList01(L);

	//排序
	L.sort(); //默认的排序规则 从小到大
	cout << "从小到大排序后 :";
	showList01(L);

	L.sort(My_sortway); //指定规则,从大到小
	cout << "从大到小排序后 :";
	showList01(L);


int main() 

	test01();

	system("pause");

	return 0;


运行结果

list实战(学生成绩管理系统)

题目要求:
1 .制作一个学生成绩单管理系统
2 .将student自定义数据类型进行排序,student中属性有姓名、年龄、语文成绩,数学成绩,英语成绩
排序规则:按照总成绩sum进行降序,如果总成绩sum相同按照语文成绩进行降序

源代码

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

class Student 
public:
	Student(string name, int ch, int ma,int e) 
		m_Name = name;
		chinese = ch;
		math = ma;
		English = e;
		sum = ch + ma + e;
	

public:
	string m_Name;  //姓名
	int chinese;      //语文成绩
	int math;   //数学成绩
	int English;//英语成绩
	int sum;//总成绩

;


bool ComparePerson(Student& p1, Student& p2)//定义sort排序从大到小


	if (p1.sum == p2.sum) 
		return p1.sum < p2.sum;
	
	else
	
		return  p1.chinese < p2.chinese;
	



void test() 

	list<Student> k;

	Student p1("杜雯菲", 88,77,95);
	Student p2("杜蚊分", 67,58,26);
	Student p3("李八八", 95,以上是关于全面理解C++STL中的list容器(附实战练习——学生成绩管理系统)的主要内容,如果未能解决你的问题,请参考以下文章

STL map&set用法详解

STL map&set用法详解

《Effective STL》阅读笔记

Docker 知识点总结 及 技术实战流程(附单独练习参考)

《Effective STL》阅读笔记

STL中vector,list,deque和map的区别