C++学习笔记(9)---deque、stack、queue、list、set、map、

本文详细介绍了C++ STL中的deque、stack、queue、list、set/multiset、map/multimap容器的使用,涉及数据结构、排序、打分案例及员工分组实践。学习如何高效地操作这些容器及其特性,如deque的高效头部操作和自定义排序规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1 deque容器

 2 案例---评委打分

3 stack容

 4 queue容器

 5 list容器---链表

6 set/multiset容器

7 map/multimap容器

8 案例---员工分组


1 deque容器

1.1 deque容器基本概念---双端数组,可以对头端进行插入删除操作

1、deque与vector区别:

(1)vector对于头部的插入删除效率低,数据量越大,效率越低;

(2)deque相对而言,对头部的插入删除速度比vector快;

(3)vector访问元素的速度会比deque快,这和两者内部实现有关;

deque容器的迭代器也是支持随机访问的

 1.1 deque构造函数-头文件<deque>

void MyPrint(const deque<int>& d)//传入const防止修改
{
    for(deque<int>::const_iterator it=d.begin();it!=d.end();it++)
        cout<<*it<<" ";
}

 1.2 deque容器-赋值操作

1.3 deque容器-大小操作 ,没有容量概念

1.4 deque容器-插入和删除

deque<int>::iterator it=d1.begin();
it++;
d1.erase(it);

总结:插入和删除提供的位置是迭代器(指针)!!!

 1.5 deque容器-数据存取

总结:除了用迭代器获取deque容器中的元素,[]和at也可以 

1.6 deque容器-排序操作---包含头文件<algorithm>

 总结:(1)排序,默认排序规则,从小到大,升序;

(2)对于支持随机访问的迭代器的容器,都可以利用sort算法直接对其进行排序

(3)vector容器也可以利用sort进行排序;

 2 案例---评委打分

有5名选手ABCDE,10个评委分别对每一名选手打分,去除最高分,最低分,取平均分

实现步骤:

(1)创建5名选手,放到vector中;

(2)遍历vector容器,取出来每一个选手,执行for循环,把10个评分打分存到deque容器中;

(3)sort算法对deque容器中分数排序,去除最高分和最低分;

(4)deque容器遍历一遍,累加总分;

(5)获取平均分

//-------------练习1:List排序练习-------------------------
/*
将Person自定义数据类型进行排序,Person中属性有姓名、年龄、身高;
排序规则:按照年龄进行升序,如果年龄相同按照身高进行降序;
*/
//创建Person类
class Person
{
public:
	Person(string name,int age,int height)
	{
		this->m_Name=name;
		this->m_Age=age;
		this->m_Height=height;
	}
	string m_Name;//姓名
	int m_Age;//年龄
	int m_Height;//身高
};
//自定义排序函数
bool MySort(Person& P1,Person& P2)
{
	if(P1.m_Age==P2.m_Age)
		return P1.m_Height>P2.m_Height;//身高降序
	else
		return P1.m_Age<P2.m_Age;//年龄升序
}
void Show(list<Person>& L)
{
	for(list<Person>::iterator it=L.begin();it!=L.end();it++)
	{
		cout<<"姓名:"<<(*it).m_Name<<" 年龄:"<<it->m_Age<<" 身高"<<(*it).m_Height<<endl;
	}
}
void test()
{
	//创建对象
	Person P1("aaa",20,175);
	Person P2("aaa",50,180);
	Person P3("aaa",40,185);
	Person P4("aaa",40,190);
	Person P5("aaa",40,195);
	Person P6("aaa",10,200);
	//创建List容器
	list<Person> L;
	//填充数据-尾插法
	L.push_back(P1);
	L.push_back(P2);
	L.push_back(P3);
	L.push_back(P4);
	L.push_back(P5);
	L.push_back(P6);
	Show(L);
	//排序
	L.sort(MySort);
	cout<<"--------------------------------------"<<endl;
	//显示
	Show(L);
}
int main()
{
	test();
	return 0;
}

3 stack容器

3.1 stack概念---一种先进后出(First In Last Out,FILO)的数据结构,只有一个出口

栈中只有顶端的元素才可以被外界使用,

因此栈不允许有遍历行为,

栈中进入数据为---入栈(push);

栈中弹出数据为---出栈(pop);

3.2 stack常用接口

 4 queue容器

4.1 queue概念---先进先出(First In First Out,FIFO)的数据结构,有两个出口

(1)队列容器允许从一端新增元素,从另一端移除元素;

(2)队列中只有队头和队尾才可以被外界使用,因此队列不允许有遍历行为;

(3)队列中进数据为---入队(push),队列中出数据为---出队(pop)

4.2 queue容器常用接口

 5 list容器---链表

5.1 list基本概念

功能:将数据进行链式存储

链表(list)是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的。链表由一系列结点组成。

结点的组成:一个是存储数据元素的数据域,另一个是存储下一个结点的指针域

STL中的链表List是一个双向循环链表;

由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器。

链表的优点:

(1)采用动态存储分配,不会造成内存浪费和溢出;

(2)链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素;

链表的缺点:

(1)链表灵活,但是空间(指针域+数据域)和时间(遍历)额外耗费较大;

List哟一个重要性质,插入操作和删除操作都不会造成原有List迭代器的失效,这在vector不成立;

总结:STL中List和Vector是最常被使用的容器,各有优缺点;

5.2 List 构造函数

 5.3 List 赋值和交换

 5.4 List 大小操作

 5.5 List 插入和删除

注意:pos一般都是迭代器(指针)

5.6 List 数据存取

总结:list容器不可以通过[]或者at方式访问数据; 

 5.7 List 反转和排序---将容器中的元素反转,以及将容器中的数据进行排序

 

总结:所有不支持随机访问迭代器的容器,不可以用标准算法;

不支持随机访问迭代器的容器,内部会提供对应算法,自己的成员函数;

默认排序规则为从小到大,升序;

5.8 排序案例

//-------------练习1:List排序练习-------------------------
/*
将Person自定义数据类型进行排序,Person中属性有姓名、年龄、身高;
排序规则:按照年龄进行升序,如果年龄相同按照身高进行降序;
*/
//创建Person类
class Person
{
public:
	Person(string name,int age,int height)
	{
		this->m_Name=name;
		this->m_Age=age;
		this->m_Height=height;
	}
	string m_Name;//姓名
	int m_Age;//年龄
	int m_Height;//身高
};
//自定义排序函数
bool MySort(Person& P1,Person& P2)
{
	if(P1.m_Age==P2.m_Age)
		return P1.m_Height>P2.m_Height;//身高降序
	else
		return P1.m_Age<P2.m_Age;//年龄升序
}
//显示函数
void Show(list<Person>& L)
{
	for(list<Person>::iterator it=L.begin();it!=L.end();it++)
	{
		cout<<"姓名:"<<(*it).m_Name<<" 年龄:"<<it->m_Age<<" 身高"<<(*it).m_Height<<endl;
	}
}
void test()
{
	//创建对象
	Person P1("aaa",20,175);
	Person P2("aaa",50,180);
	Person P3("aaa",40,185);
	Person P4("aaa",40,190);
	Person P5("aaa",40,195);
	Person P6("aaa",10,200);
	//创建List容器
	list<Person> L;
	//填充数据-尾插法
	L.push_back(P1);
	L.push_back(P2);
	L.push_back(P3);
	L.push_back(P4);
	L.push_back(P5);
	L.push_back(P6);
	Show(L);
	//排序
	L.sort(MySort);
	cout<<"--------------------------------------"<<endl;
	//显示
	Show(L);
}
int main()
{
	test();
	return 0;
}

6 set/multiset容器

6.1 set概念---所有元素都会在插入时自动被排序

本质:set/multiset属于关联式容器,底层结构是用二叉树实现。

set和multiset区别:(1)set不允许容器中由重复的元素;(2)multiset允许容器中有重复的元素;

6.2 set 构造和赋值---创建set容器以及赋值

 

 

 

6.3 set 大小和交换

 

 

6.4 set 插入和删除 

 

 

 

 6.5 set 查找和统计

 6.6 set和multiset的区别

 (1)set不可以插入重复数据,而multiset可以;

(2)set插入数据的同时会返回插入结果,表示插入是否成功;

(3)multiset不会检测数据,因此可以插入重复数据;

//------------练习2:set(二叉树)容器练习---------
void PrintSet(const set<int>& s)
{
	for(set<int>::const_iterator it=s.begin();it!=s.end();it++)
	{
		cout<<(*it)<<endl;
	}
}
void PrintMultiSet(const multiset<int>& ms)
{
	for(multiset<int>::iterator it=ms.begin();it!=ms.end();it++)
	{
		cout<<(*it)<<endl;
	}
}
void test()
{
	set<int>s;
	pair<set<int>::iterator,bool>ret=s.insert(10);//返回对组数据类型
	PrintSet(s);
	if(ret.second)
		cout<<"第一次插入成功!"<<endl;
	else
		cout<<"第一次插入失败!"<<endl;
	ret=s.insert(10);
	if(ret.second)
		cout<<"第二次插入成功!"<<endl;
	else
		cout<<"第二次插入失败!"<<endl;
	
	multiset<int>ms;
	ms.insert(10);
	ms.insert(10);
	PrintMultiSet(ms);
}
int main()
{
	test();
	return 0;
}

 6.7 pair对组创建---成对出现的数据,利用对组可以返回两个数据

 

pair<string,int>p1=make_pair("Jerry",30);
cout<<"姓名:"<<p1.first<<" 年龄:"<<p1.second<<endl;

6.8 set容器排序

set容器默认排序规则为从小到大,利用仿函数,可以改变排序规则;

//--------------练习3:set容器排序--------------
//(1)内置数据类型排序
class MySort
{
public:
	bool operator()(int v1,int v2)//重载()
	{
		return v1>v2;//修改为降序
	}
};
void test01()
{
	set<int>s1;//默认为从小到大,升序排列
	s1.insert(20);
	s1.insert(30);
	s1.insert(10);
	s1.insert(70);
	s1.insert(0);
	for(set<int>::iterator it=s1.begin();it!=s1.end();it++)
	{
		cout<<(*it)<<" ";
	}
	cout<<endl;
	//修改为降序,必须在插入数据之前进行设置
	set<int,MySort>s2;//<>只能放数据类型,不可以放函数名,因此创建类
	s2.insert(2);
	s2.insert(3);
	s2.insert(1);
	s2.insert(7);
	s2.insert(10);
	for(set<int,MySort>::iterator it=s2.begin();it!=s2.end();it++)
	{
		cout<<(*it)<<" ";
	}
	cout<<endl;
}
//(2)自定义数据类型,都会制定排序规则,否则不知道怎么插入数据
class Person
{
public:
	Person(string name,int age)
	{
		this->m_Name=name;
		this->m_Age=age;
	}
	string m_Name;
	int m_Age;
};
class MySort02
{
public:
	bool operator()(const Person&P1,const Person&P2)
	{
		return P1.m_Age>P2.m_Age;
	}
};
void test02()
{
	Person P1("aaa",24);
	Person P2("aaa",22);
	Person P3("aaa",20);
	Person P4("aaa",28);
	set<Person,MySort02>s;
	s.insert(P1);
	s.insert(P2);
	s.insert(P3);
	s.insert(P4);
	for(set<Person>::iterator it=s.begin();it!=s.end();it++)
	{
		cout<<"姓名:"<<(*it).m_Name<<" 年龄:"<<it->m_Age<<endl;
	}
	cout<<endl;
}
int main()
{
	//test01();//内置数据类型修改排序
	test02();//自定义数据类型
	return 0;
}

7 map/multimap容器

7.1 map概念

(1)map中所有元素都是pair;(2)所有元素都会根据元素的键值自动排序;

(3)pair中的第一个元素为key(键值),起到索引作用,第二个元素为value(实值)

本质:map/multimap属于关联式容器,底层结构是用二叉树实现。

优点:可以根据Key值快速找到value值;

map和multimap的区别:(1)map不允许容器中有重复的Key值元素;

(2)multimap允许容器中有重复的Key值元素

7.2 map容器 构造和赋值

 

 

 

//---------------练习4:map容器构造赋值-----------
void PrintMap(const map<int,int>&m)
{
	for(map<int,int>::const_iterator it=m.begin();it!=m.end();it++)
	{
		cout<<"Key为:"<<(*it).first<<" 实值:"<<it->second<<endl;
	}
}
void test()
{
	//默认构造
	map<int,int>m;//创建Map容器,数据要是对组形式,键值+实值
	m.insert(pair<int,int>(2,10));//pair构造,匿名对象直接插入后注销
	m.insert(pair<int,int>(5,10));//插入时会自动按key排序
	m.insert(pair<int,int>(1,10));
	m.insert(pair<int,int>(7,10));
	PrintMap(m);
	//拷贝构造
	map<int,int>m2(m);
	PrintMap(m2);
	//赋值
	map<int,int>m3;
	m3=m2;
	PrintMap(m3);
}
int main()
{
	test();
	return 0;
}

 总结:map中所有元素都是成对出现,插入数据时候要是用对组;

7.3 map大小和交换

 

 

 7.4 map容器-插入和删除

 注意:这个elem要是对组形式

m.insert(pair<int,int>(1,10));//第一种
m.insert(make_pair(2,20));//第二种-----------------推荐!!
m.inset(map<int,int>::value_type(3,30));//第三种
m[4]=40;//第四种---不建议插入使用,但是可以利用Key访问到value,m[2]

7.5 map容器-查找和统计

//---------------练习5:map容器的查找和统计---------
void test()
{
	map<int,int>m;
	m.insert(make_pair(1,20));
	m.insert(make_pair(2,30));
	m.insert(make_pair(3,40));
	for(map<int,int>::iterator it=m.begin();it!=m.end();it++)
	{
		cout<<"键值:"<<(*it).first<<" 实值:"<<it->second<<endl;
	}
	map<int,int>::iterator pos=m.find(3);//返回迭代器!!
	if(pos!=m.end())
		cout<<"找到"<<(*pos).first<<" "<<pos->second<<endl;//根据返回的迭代器找键值和实值
	else
		cout<<"找不到"<<endl;
	cout<<"键值为2的元素个数"<<m.count(2)<<endl;
}
int main()
{
	test();
	return 0;
}

7.6 map容器-排序(默认从小到大,升序)---利用仿函数,改变排序规则

8 案例---员工分组

//案例描述
/*
公司今天招聘了10个员工(ABCDEFGHIJ),10名员工进入公司之后,需要指派员工在那个部门工作
员工信息有:姓名、工资组成;部门有:策划、美术、研发
随机给10名员工分配部门和工资
通过multimap进行信息的插入 key(部门编号)vlaue(员工)
分部门显示员工信息
	*/
//实现步骤
/*
1、创建10名员工,放到vector中
2、遍历vector容器,取出每个员工,进行随机分组
3、分组后,将员工部门编号作为key,具体员工工作为value,放入到Multimap容器中
4、分部门显示员工信息
*/
class Worker
{
public:
	/*Worker(string name,int salary)
	{
		this->m_Name=name;
		this->m_Salary=salary;
	}*/
	string m_Name;
	int m_Salary;
};
void CreateWorker(vector<Worker>& v)
{
	string seed="ABCDEFGHIJ";
	for(int i=0;i<10;i++)
	{
		Worker W;
		W.m_Name=seed[i];
		W.m_Salary=rand()%10000+10000;
		v.push_back(W);
	}
}
void ShowVector(const vector<Worker>&v)
{
	for(vector<Worker>::const_iterator it=v.begin();it!=v.end();it++)
	{
		cout<<"员工姓名:"<<it->m_Name<<" 员工工资:"<<it->m_Salary<<endl;
	}
}
void DepartWorker(vector<Worker>&v,multimap<int,Worker>&m)
{
	for(vector<Worker>::iterator it=v.begin();it!=v.end();it++)
	{
		int ret=rand()%3;
		m.insert(make_pair(ret,(*it)));
	}
}
void PrintMap(const multimap<int,Worker>&m)
{
	//策划
	multimap<int,Worker>::const_iterator pos=m.find(SCHEME);//返回迭代器
	int num=0;
	int count=m.count(SCHEME);
	cout<<"策划部门:"<<endl;
	for(;pos!=m.end() && num<count;pos++,num++)
	{
		cout<<"员工姓名:"<<pos->second.m_Name<<" 员工工资:"<<pos->second.m_Salary<<endl;
	}
	//美术
	pos=m.find(ART);//返回迭代器
	count=m.count(ART);
	cout<<"美术部门:"<<endl;
	for(num=0;pos!=m.end() && num<count;pos++,num++)
	{
		cout<<"员工姓名:"<<pos->second.m_Name<<" 员工工资:"<<pos->second.m_Salary<<endl;
	}
	//研发
	pos=m.find(TECH);//返回迭代器
	count=m.count(TECH);
	cout<<"研发部门:"<<endl;
	for(num=0;pos!=m.end() && num<count;pos++,num++)
	{
		cout<<"员工姓名:"<<pos->second.m_Name<<" 员工工资:"<<pos->second.m_Salary<<endl;
	}
}
int main()
{
	srand((unsigned int)time(NULL));
	//1、创建员工,放入vector中
	vector<Worker>v;
	CreateWorker(v);
	//测试
	//ShowVector(v);
	//2、遍历vector容器,取出每个员工,进行随机分组
	multimap<int,Worker>m;
	DepartWorker(v,m);
	//3、分部门显示员工信息
	PrintMap(m);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值