从0到1入门C++编程——10 stack容器、queue容器、list容器、set容器、map容器

文章目录

  • 一、stack容器
  • 二、queue容器
  • 三、list容器
    • 1、构造函数
    • 2、赋值和交换
    • 3、大小及判空
    • 4、插入和删除
    • 5、数据存取
    • 6、反转和排序
    • 7、排序案例
  • 四、set/multiset容器
    • 1、构造和赋值
    • 2、大小和交换
    • 3、插入和删除
    • 4、查找和统计
    • 5、set和multiset的区别
    • 6、pair对组的创建
    • 7、排序及规则改变
  • 五、map/multimap容器
    • 1、构造和赋值
    • 2、大小和交换
    • 3、插入和删除
    • 4、查找和统计
    • 5、排序及规则改变
  • 六、员工分组案例

一、stack容器

stack是一种后进先出的数据结构,栈中只有栈顶元素才可以被外界使用,所以栈不允许有遍历行为。
栈可以进行判空操作,也可以统计栈中的元素数量。
stack容器常用的接口有以下几个。

//构造函数
stack<T> stk;  //默认构造函数
stack(const stack &stk);  //拷贝构造函数
//赋值操作
stack& operator=(const stack &stk);  //=赋值操作
//数据存取
push(elem);  //向栈顶添加元素
pop();  //删除栈顶元素
top();  //返回栈顶元素
//大小操作
empty();  //判空
size();  //返回栈的大小

关于栈容器的简单操作示例如下。

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

void fun()
{
	stack<int> s;
	s.push(1);
	s.push(2);
	s.push(3);
	s.push(4);
	cout<<"栈的大小为:"<<s.size()<<endl;
	while(!s.empty())
	{
		cout<<"栈顶元素:"<<s.top()<<endl;
		s.pop();  //出栈
	}
	cout<<"栈的大小为:"<<s.size()<<endl;
}

int main()
{
	fun();
	system("pause");
	return 0;
}

上面程序的运行结果如下图所示。
在这里插入图片描述


二、queue容器

queue是一种先进先出的数据结构,queue容器允许从一端新增元素,从另一端移除元素。队列中只有队头和队尾才可以被外界使用,因此队列不允许有遍历行为。
queue容器常用的接口有以下几个。

//构造函数
queue<T> que;  //默认构造函数
queue(const queue &que);  //拷贝构造函数
//赋值操作
queue& operator=(const queue &que);  //=赋值操作
//数据存取
push(elem);  //往队尾添加元素
pop();  //删除队头元素
back();  //返回最后一个元素
front();  //返回第一个元素
//大小操作
empty();  //判空
size();  //返回队列的大小

关于队列容器的简单操作示例如下。

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

void fun()
{
	queue<int> q;
	q.push(1);
	q.push(2);
	q.push(3);
	q.push(4);
	cout<<"队列的大小为:"<<q.size()<<endl;
	while(!q.empty())
	{
		cout<<"队头元素:"<<q.front()<<endl;
		cout<<"队尾元素:"<<q.back()<<endl;
		q.pop();
	}
	cout<<"队列的大小为:"<<q.size()<<endl;
}

int main()
{
	fun();
	system("pause");
	return 0;
}

三、list容器

链表由一系列结点组成,结点由存储数据元素的数据域和存储下一个结点地址的指针域构成。
链表将数据进行链式存储,是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的。STL中的链表是一个双向循环链表。
链表的优点是其采用动态存储分配,不会造成内存的浪费和溢出,而且链表执行插入和删除操作十分方便,只需要修改指针,不需要移动大量元素。缺点是遍历的速度没有数组快,因为数据不是连续存放的,此外,链表占用的空间也比数组大,相比于数组只存放数据,链表还需要存放地址。
在这里插入图片描述
由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移操作,也就是只能做++和–运算,不能一次跳几个,其属于双向迭代器。
list容器有一个重要的性质,插入和删除操作都不会造成原有list迭代器的失效。这在vector中是不成立的,如果将vector的容量进行扩充,那么其迭代器就会失效。

1、构造函数

list容器常用的接口有以下几个。

list<T> lst;  //默认构造函数
list(begin,end);  //将区间元素进行拷贝
list(n,elem);   //将n个元素进行拷贝
list(const list &lst);  //拷贝构造函数

关于list容器构造函数的简单代码示例如下。

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

void printList(const list<int> &L)
{
	for(list<int>::const_iterator i=L.begin();i!=L.end();i++)
	{
		cout<<*i<<" ";
	}
	cout<<endl;
}

void fun()
{
	list<int> L1;  //默认构造
	L1.push_back(1);
	L1.push_back(2);
	L1.push_front(3);
	L1.push_front(4);
	printList(L1);
	list<int> L2(L1.begin(),L1.end());  //复制区间构造
	printList(L2);
	list<int> L3(5,6);  //指定长度和元素构造
	printList(L3);
	list<int> L4(L3);  //拷贝构造
	printList(L4);
}

int main()
{
	fun();
	system("pause");
	return 0;
}

2、赋值和交换

与前面介绍过的容器一样,list容器赋值包括=赋值和assign赋值,交换仍然使用swap()函数。
关于list容器赋值和交换的简单示例如下。

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

void printList(const list<int> &L)
{
	for(list<int>::const_iterator i=L.begin();i!=L.end();i++)
	{
		cout<<*i<<" ";
	}
	cout<<endl;
}

void fun()
{
	list<int> L1;
	L1.push_back(1);
	L1.push_back(2);
	L1.push_front(3);
	L1.push_front(4);
	cout<<"L1 : ";
	printList(L1);
	list<int> L2;
	L2 = L1;  // = 赋值
	cout<<"L2 : ";
	printList(L2);
	list<int> L3;
	L3.assign(L2.begin(),L2.end());   //assign区间赋值
	cout<<"L3 : ";
	printList(L3);
	list<int> L4;
	L4.assign(6,6);   //指定数字赋值
	cout<<"L4 : ";
	printList(L4);
	L1.swap(L4);  //使用swap()交换两个容器
	cout<<"交换L1和L4后:"<<endl;
	cout<<"L1 : ";
	printList(L1);
	cout<<"L4 : ";
	printList(L4);
}

int main()
{
	fun();
	system("pause");
	return 0;
}

上面程序运行后的结果如下图所示。
在这里插入图片描述

3、大小及判空

list容器的大小及判空操作与前面介绍的容器一样,简单的代码示例如下。

void fun()
{
	list<int> L1;
	L1.push_back(1);
	L1.push_back(2);
	L1.push_front(3);
	L1.push_front(4);
	printList(L1);
	if(!L1.empty())
	{
		cout<<"容器不为空!"<<endl;
		cout<<"容器中的元素个数:"<<L1.size()<<endl;
	}
	L1.resize(7);
	printList(L1);
	L1.resize(10,6);
	printList(L1);
}

4、插入和删除

插入和删除的主要函数接口有以下几个。

push_front(elem);  //在容器头部插入一个数据
push_back(elem);  //在容器尾部插入一个数据
pop_front();  //从容器头部删除一个数据
pop_back();  //从容器尾部删除一个数据

insert(pos,elem);  //在指定位置插入指定元素,要用迭代器,不能用数字索引
insert(pos,n,elem);  //在指定位置插入n个指定元素
insert(pos,start_pos,end_pos); //从指定位置开始插入区间数据
clear(); //清空数据
erase(pos); //删除指定位置的数据
erase(start_pos,end_pos);  //删除指定区间的数据
remove(elem);  //删除容器中所有和elem值匹配的元素

关于插入和删除的操作,list容器中多了一个remove操作,简单的示例如下。

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

void printList(const list<int> &L)
{
	for(list<int>::const_iterator i=L.begin();i!=L.end();i++)
	{
		cout<<*i<<" ";
	}
	cout<<endl;
}

void fun()
{
	list<int> L1;
	L1.push_back(1);
	L1.push_front(2);
	printList(L1);
	L1.insert(L1.begin(),3);
	L1.insert(++L1.begin(),4,6);
	printList(L1);
	L1.erase(--L1.end());
	printList(L1);
	L1.remove(6);   //移除容器中所有的6
	printList(L1);
}

int main()
{
	fun();
	system("pause");
	return 0;
}

上面程序运行后的结果如下图所示。
在这里插入图片描述

5、数据存取

list容器不同于vector和deque容器,其数据存取不支持中括号[]和at()方式,只能使用front()和back()返回第一个和最后一个元素。
关于list容器数据存取操作的简单代码示例如下。

void fun()
{
	list<int> L1;
	L1.push_back(1);
	L1.push_front(2);
	L1.push_back(3);
	L1.push_front(4);
	printList(L1);
	cout<<"第一个元素为: "<<L1.front()<<endl;
	cout<<"最后一个元素为: "<<L1.back()<<endl;
}

验证迭代器是不是支持随机访问且是双向的。

list<int>::iterator i=L.begin();
i++;
i--;  //i++和i--都不报错就是支持双向访问
i = i+1;  //报错就说明不支持随机访问

6、反转和排序

list容器的反转和排序分别使用下面的函数。

reverse();  //反转链表
sort();   //将链表进行排序,成员函数,非全局函数

由于迭代器在list容器中不可以随机访问,因此不能使用标准的算法,但是内部会提供一些函数接口,使用.访问,而不是全局函数。
list容器的反转和排序简单示例如下。

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

void printList(const list<int> &L)
{
	for(list<int>::const_iterator i=L.begin();i!=L.end();i++)
	{
		cout<<*i<<" ";
	}
	cout<<endl;
}

bool myrule(int a,int b)  //排序规则
{
	return a > b;
}

void fun()
{
	list<int> L1;
	L1.push_back(2);
	L1.push_back(1);
	L1.push_back(4);
	L1.push_back(3);
	cout<<"原序列 :";
	printList(L1);
	L1.reverse();
	cout<<"原序列反转后 :";
	printList(L1);
	L1.sort();  //默认升序排列
	cout<<"原序列升序排列后 :";
	printList(L1);
	L1.sort(myrule);  //降序排列
	cout<<"原序列降序排列后 :";
	printList(L1);
}

int main()
{
	fun();

	system("pause");
	return 0;
}

上面程序运行后的结果如下图所示。
在这里插入图片描述

7、排序案例

将自定义数据类型Person进行排序,排序按照年龄升序排列,如果年龄相同则按照身高降序排列。Person中的属性包括姓名、年龄、身高。
该案例的代码实现如下。

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

class Person
{
public:
	Person(string name,int age,int height)
	{
		this->name = name;
		this->age = age;
		this->height = height;
	}
	string name;
	int age;
	int height;
};

void printList(const list<Person> &L)
{
	for(list<Person>::const_iterator i=L.begin();i!=L.end();i++)
	{
		cout<<"姓名: "<<(*i).name<<" 年龄: "<<(*i).age<<" 身高: "<<(*i).height<<endl;
	}
}

bool sortPerson(Person &p1,Person &p2)  //排序规则
{
	if(p1.age == p2.age)
	{
		return p1.height > p2.height;  //在年龄相同时按照身高降序
	}
	return p1.age<p2.age;  //按照年龄升序排列
}

void fun()
{
	Person p1("A",20,185);
	Person p2("B",20,175);
	Person p3("C",20,176);
	Person p4("D",18,191);
	Person p5("E",23,186);
	list<Person> L;
	L.push_back(p1);
	L.push_back(p2);
	L.push_back(p3);
	L.push_back(p4);
	L.push_back(p5);
	cout<<"------------排序前------------"<<endl;
	printList(L);
	L.sort(sortPerson);
	cout<<"------------排序后------------"<<endl;
	printList(L);
}

int main()
{
	fun();

	system("pause");
	return 0;
}

上面程序运行后的结果如下图所示。
在这里插入图片描述
本案例中涉及到对自定义数据类型的排序,需要自己指定相应的排序规则,然后传入sort()函数中即可。


四、set/multiset容器

set/multiset容器的特点是所有元素在插入时自动被排序,容器的本质是关联式容器,底层结构用二叉树实现。
set容器和multiset容器的区别在于,set容器不允许容器中有重复的元素,而multiset容器中允许出现重复的元素。
set/multiset容器插入数据时没有push()或push_back(),只能用insert()函数来插入数值。

1、构造和赋值

构造包括默认构造和拷贝构造,赋值通过=实现。
set容器关于构造和赋值的操作示例如下。

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

void printSet(const set<int> &s)
{
	for(set<int>::const_iterator i=s.begin();i!=s.end();i++)
	{
		cout<<*i<<" ";
	}
	cout<<endl;
}

void fun()
{
	set<int> s1;    //默认构造
	s1.insert(2);  //插入数据用insert()
	s1.insert(1);
	s1.insert(2);
	s1.insert(4);
	s1.insert(2);
	s1.insert(3);
	cout<<"s1 : ";
	printSet(s1);
	set<int> s2(s1);  //拷贝构造
	cout<<"s2 : ";
	printSet(s2);
	set<int> s3;
	s3 = s1;  //赋值操作
	cout<<"s3 : ";
	printSet(s3);
}

int main()
{
	fun();
	system("pause");
	return 0;
}

上面程序运行后的结果如下图所示。
在这里插入图片描述
可以看到,在set容器中插入重复数据虽然不会报错,但也不会打印出来,而且插入无序的元素在打印的时候被排好序了。

2、大小和交换

set容器不支持重新定义容器大小,即没有resize()函数。
关于set容器大小、判空和交换的简单应用如下。

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

void printSet(const set<int> &s)
{
	for(set<int>::const_iterator i=s.begin();i!=s.end();i++)
	{
		cout<<*i<<" ";
	}
	cout<<endl;
}

void fun()
{
	set<int> s1;
	s1.insert(2);
	s1.insert(1);
	s1.insert(4);
	s1.insert(3);
	cout<<"s1 : ";
	printSet(s1);
	if(!s1.empty())
	{
		cout<<"容器非空,大小为: "<<s1.size()<<endl;
	}
	set<int> s2;
	s2.insert(20);
	s2.insert(10);
	s2.insert(40);
	s2.insert(30);
	cout<<"s2 : ";
	printSet(s2);
	cout<<"交换s1和s2容器后: "<<endl;
	s1.swap(s2);
	cout<<"s1 : ";
	printSet(s1);
	cout<<"s2 : ";
	printSet(s2);
}

int main()
{
	fun();

	system("pause");
	return 0;
}

上面程序运行后的结果如下图所示。
在这里插入图片描述

3、插入和删除

set容器插入使用insert()函数,删除使用erase()函数,清空容器使用clear()函数。在使用erase()函数时,既可以传入迭代器的位置,也可以传入要删除的元素,当然也可以传入一个区间进行删除,传入迭代器的首尾位置,其作用和clear()函数一样。
关于set容器插入和删除的简单操作示例如下。

void fun()
{
	set<int> s1;
	s1.insert(2);
	s1.insert(1);
	s1.insert(4);
	s1.insert(3);
	printSet(s1);
	s1.erase(s1.begin());  //指定迭代器的位置进行删除
	printSet(s1);
	s1.erase(3);  //指定容器中的元素进行删除
	printSet(s1);
	s1.clear();  //清空容器,等价于 s1.erase(s1.begin(),s1.end());
	printSet(s1);
}

4、查找和统计

set容器中进行查找使用的函数是find(elem),查找元素elem是否存在,其返回值是一个迭代器,如果该元素存在,就返回该元素的迭代器,如果不存在,就返回end()。
set容器中统计元素的个数使用的函数是count(elem),但是其结果只能是0或1,对于multiset容器而言,count(elem)的结果可能大于1。

find(elem);  //返回的是迭代器的位置
count(elem);  //返回元素个数

关于set容器查找和统计的代码示例如下。

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

void printSet(const set<int> &s)
{
	for(set<int>::const_iterator i=s.begin();i!=s.end();i++)
	{
		cout<<*i<<" ";
	}
	cout<<endl;
}

void fun()
{
	set<int> s1;
	s1.insert(2);
	s1.insert(1);
	s1.insert(2);
	s1.insert(2);
	s1.insert(4);
	s1.insert(3);
	printSet(s1);
	set<int>::iterator pos = s1.find(2);
	if(pos!=s1.end())
	{
		cout<<"元素"<<*pos<<"存在!"<<endl;
		cout<<"元素"<<*pos<<"的个数: "<<s1.count(*pos)<<endl;
	}
	else
	{
		cout<<"元素不存在!"<<endl;
	}
}

int main()
{
	fun();

	system("pause");
	return 0;
}

上面程序运行后的结果如下图所示。
在这里插入图片描述

5、set和multiset的区别

set不可以插入重复数据,其在插入的同时会返回插入结果,反馈是否插入成功,multiset不会检测数据,所以允许插入重复的数据。
set使用插入insert()时,转到其定义如下,再转到Pairib的定义。

template<class _Valty>
		_Pairib insert(_Valty&& _Val)
		{	// try to insert node with value _Val, favoring right side
		return (_Linsert(this->_Buynode(_STD forward<_Valty>(_Val)),
			false));
		}

typedef pair<iterator, bool> _Pairib;   //pair是对组,返回的不仅有迭代器,还有bool类型,即插入成功与否

multiset使用插入insert()时,转到其定义如下。

template<class _Valty>
		iterator insert(_Valty&& _Val)
		{	// insert a {key, mapped} value
		return (_Mybase::insert(_STD forward<_Valty>(_Val)).first);
		}

可以看到,multiset在插入时返回值是一个迭代器类型,不像set容器返回的是pair对组,因此在插入时不做判断,即使元素重复也能插入成功。
关于set和multiset容器的区别,简单的代码示例如下。

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

void printSet(const multiset<int> &ms)
{
	for(multiset<int>::const_iterator i=ms.begin();i!=ms.end();i++)
	{
		cout<<*i<<" ";
	}
	cout<<endl;
}

void fun1()
{
	set<int> s;
	pair<set<int>::iterator,bool> ret = s.insert(2);
	if(ret.second)
	{
		cout<<"元素第一次插入成功!"<<endl;
	}
	else
	{
		cout<<"元素第一次插入失败!"<<endl;
	}
	ret = s.insert(2);
	if(ret.second)
	{
		cout<<"元素第二次插入成功!"<<endl;
	}
	else
	{
		cout<<"元素第二次插入失败!"<<endl;
	}
}

void fun2()   // multiset容器测试
{
	multiset<int> ms;
	ms.insert(2);
	ms.insert(2);
	ms.insert(2);
	printSet(ms);
}

int main()
{
	fun1();
	fun2();
	system("pause");
	return 0;
}

上面程序运行后的结果如下图所示。
在这里插入图片描述

6、pair对组的创建

对组是指成对出现的数据,利用对组可以返回两个数据。
对组的两种创建方式如下。

pair<type,type> p(value1,value2);
pair<type,type> p = make_pair(value1,value2);

关于对组的简单应用代码如下。

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

void fun()
{
	pair<string,int> p1("Tom",10);  //方式一
	cout<<"name: "<<p1.first<<"  age: "<<p1.second<<endl;
	pair<string,int> p2 = make_pair("Jack",20);   //方式二
	cout<<"name: "<<p2.first<<"  age: "<<p2.second<<endl;
}

int main()
{
	fun();
	system("pause");
	return 0;
}

上面程序运行后的结果如下图所示。
在这里插入图片描述

7、排序及规则改变

set容器默认排序规则为从小到大,使用仿函数就可以改变排序规则。
使用仿函数改变内置数据类型排序规则的代码示例如下。

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

class Compare
{
public:
	bool operator()(int a,int b)  //重载()
	{
		return a > b;
	}
};

void printSet(set<int,Compare> &s)
{
	for(set<int,Compare>::iterator i=s.begin();i!=s.end();i++)
	{
		cout<<*i<<" ";
	}
	cout<<endl;
}

void fun()
{
	set<int,Compare> s1;  //尖括号里携带的是类型,不能是函数
	s1.insert(2);
	s1.insert(3);
	s1.insert(1);
	s1.insert(4);
	printSet(s1);
}

int main()
{
	fun();
	system("pause");
	return 0;
}

上面程序运行后输出的元素就是按照降序排列的。
使用仿函数改变自定义数据类型排序规则的代码示例如下。

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

class Person
{
public:
	Person(string name,int age)
	{
		this->name = name;
		this->age = age;
	}
	string name;
	int age;
};

class Compare
{
public:
	bool operator()(const Person &p1,const Person &p2)  //重载(),规定排序类型
	{
		return p1.age > p2.age;  //按年龄降序排列
	}
};

void printSet(set<Person,Compare> &s)
{
	for(set<Person,Compare>::iterator i=s.begin();i!=s.end();i++)
	{
		cout<<"姓名: "<<i->name<<" 年龄: "<<i->age<<endl;
	}
}

void fun()
{
	set<Person,Compare> s1;
	Person p1("A",10);
	Person p2("B",20);
	Person p3("C",30);
	Person p4("D",40);
	s1.insert(p1);
	s1.insert(p2);
	s1.insert(p3);
	s1.insert(p4);
	printSet(s1);
}

int main()
{
	fun();
	system("pause");
	return 0;
}

上面程序运行后的结果如下图所示。
在这里插入图片描述


五、map/multimap容器

map容器中所有的元素都是对组pair型,pair中的第一个元素为key,即键值,第二个元素为value,即实值。map容器中的所有元素都会根据元素的键值自动排序。
map/multimap属于关联式容器,底层的结构是用二叉树实现的,其最大的优点是可以根据键值快速的找到value值。
map容器和multimap容器的区别在于,map容器不允许容器中有重复的键值key,而multimap容器中则允许有重复的键值。

1、构造和赋值

构造包括默认构造和拷贝构造两种,赋值通过=实现。插入操作仍然是使用insert()函数,不过在函数中需要声明类型是pair,然后再传值。
关于map容器构造和赋值的操作示例如下。

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

void printSet(map<int,int> &m)
{
	for(map<int,int>::iterator i=m.begin();i!=m.end();i++)
	{
		cout<<"key: "<<(*i).first<<" value: "<<(*i).second<<endl;
	}
}

void fun()
{
	map<int,int> m;  //默认构造
	m.insert(pair<int,int>(1,10));
	m.insert(pair<int,int>(4,40));
	m.insert(pair<int,int>(3,30));
	m.insert(pair<int,int>(2,20));
	cout<<"m : "<<endl;
	printSet(m); 
	map<int,int> m1(m);  //拷贝构造
	cout<<"m1 : "<<endl;
	printSet(m1); 
	map<int,int> m2;
	m2 = m;   //赋值操作
	cout<<"m2 : "<<endl;
	printSet(m2); 
}

int main()
{
	fun();
	system("pause");
	return 0;
}

上面程序运行后的结果如下图所示。
在这里插入图片描述

2、大小和交换

关于map容器大小、判空和交换的简单应用如下。

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

void printSet(map<int,int> &m)
{
	for(map<int,int>::iterator i=m.begin();i!=m.end();i++)
	{
		cout<<"key: "<<(*i).first<<" value: "<<(*i).second<<endl;
	}
}

void fun()
{
	map<int,int> m;  //默认构造
	m.insert(pair<int,int>(1,10));
	m.insert(pair<int,int>(2,20));
	if(!m.empty())
	{
		cout<<"容器非空,大小为: "<<m.size()<<endl;
	}
	else
	{
		cout<<"容器为空!"<<endl;
	}
	cout<<"------交换前------"<<endl;
	cout<<"m : "<<endl;
	printSet(m); 
	map<int,int> m1;
	m1.insert(pair<int,int>(3,30));
	m1.insert(pair<int,int>(4,40));
	cout<<"m1 : "<<endl;
	printSet(m1); 
	cout<<"------交换后------"<<endl;
	m.swap(m1);
	cout<<"m : "<<endl;
	printSet(m); 
	cout<<"m1 : "<<endl;
	printSet(m1); 
}

int main()
{
	fun();
	system("pause");
	return 0;
}

上面程序运行后的结果如下图所示。
在这里插入图片描述

3、插入和删除

map容器插入使用insert()函数,删除使用erase()函数,清空容器使用clear()函数。在使用erase()函数时,既可以传入迭代器的位置,也可以传入要删除的元素,当然也可以传入一个区间进行删除,传入迭代器的首尾位置,其作用和clear()函数一样。插入的方式总共有四种。
关于map容器插入和删除的简单操作示例如下。

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

void printSet(map<int,int> &m)
{
	for(map<int,int>::iterator i=m.begin();i!=m.end();i++)
	{
		cout<<"key: "<<(*i).first<<" value: "<<(*i).second<<endl;
	}
	cout<<endl;
}

void fun()
{
	map<int,int> m;
	m.insert(pair<int,int>(1,10));  //插入方式一
	m.insert(make_pair(2,20));    //插入方式二
	m.insert(map<int,int>::value_type(3,30));  //插入方式三
	m[4]=40; //插入方式四,不建议使用该方式,因为如果key在容器中不存在会自动创建一个value为0的出来
	cout<<m[5]<<endl;
	printSet(m);
	m.erase(5);  //按照键值key删除
	m.erase(m.begin());  //按照迭代器位置删除
	printSet(m);
	m.clear();  //清空,等价于m.erase(m.begin(),m.end());
	printSet(m);
 }

int main()
{
	fun();
	system("pause");
	return 0;
}

上面程序运行后的结果如下图所示。
在这里插入图片描述

4、查找和统计

map容器中进行查找使用的函数是find(elem),查找元素elem是否存在,其返回值是一个迭代器,如果该元素存在,就返回该元素的迭代器,如果不存在,就返回end()。
map容器中统计元素的个数使用的函数是count(elem),但是其结果只能是0或1,对于multimap容器而言,count(elem)的结果可能大于1。

find(elem);  //返回的是迭代器的位置
count(elem);  //返回元素个数

关于map容器查找和统计的代码示例如下。

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

void fun()
{
	map<int,int> m;
	m.insert(pair<int,int>(1,10));
	m.insert(make_pair(2,20));
	m.insert(map<int,int>::value_type(3,30)); 
	map<int,int>::iterator pos = m.find(2);
	if(pos!=m.end())
	{
		cout<<"元素存在! key = "<<(*pos).first<<"  value = "<<(*pos).second<<endl;
		cout<<"键值"<<(*pos).first<<"的个数: "<<m.count((*pos).first)<<endl;
	}
	else
	{
		cout<<"元素不存在!"<<endl;
	}
}

int main()
{
	fun();

	system("pause");
	return 0;
}

上面程序运行后的结果如下图所示。
在这里插入图片描述

5、排序及规则改变

map容器默认排序规则仍然是从小到大,通过自己写仿函数就可以改变排序规则。
使用仿函数改变内置数据排序规则的代码示例如下。

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

class Compare
{
public:
	bool operator()(int a,int b)
	{
		return a > b;
	}
};

void fun()
{
	map<int,int,Compare> m;
	m.insert(pair<int,int>(1,10));
	m.insert(make_pair(2,20));
	m.insert(map<int,int>::value_type(3,30)); 
	for(map<int,int,Compare>::iterator i=m.begin();i!=m.end();i++)
	{
		cout<<"key = "<<i->first<<" value = "<<i->second<<endl;
	}
}

int main()
{
	fun();

	system("pause");
	return 0;
}

上面程序运行后的结果如下图所示。
在这里插入图片描述
这里需要注意的是,map容器中是对key进行排序的,如果要按照自定义数据的属性进行排序,需要把自定义数据类型放在map容器的第一个位置上。
使用仿函数改变自定义数据排序规则的代码示例如下。

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

class Person
{
public:
	Person(string name,int age)
	{
		this->name = name;
		this->age = age;
	}
	string name;
	int age;
};

class Compare
{
public:
	bool operator()(Person p1,Person p2)
	{
		return p1.age > p2.age;
	}
};

void fun()
{
	map<Person,int,Compare> m;
	Person p1("Tom",10);
	Person p2("Jack",30);
	Person p3("Hole",20);
	m.insert(pair<Person,int>(p1,1));
	m.insert(pair<Person,int>(p2,2));
	m.insert(pair<Person,int>(p3,3));
	for(map<Person,int,Compare>::iterator i=m.begin();i!=m.end();i++)
	{
		cout<<"key = "<<i->second<<" name = "<<i->first.name<<" age = "<<i->first.age<<endl;
	}
}

int main()
{
	fun();

	system("pause");
	return 0;
}

上面程序运行后的结果如下图所示。
在这里插入图片描述
从输出结果可以看出,排序是按照自定义数据的年龄属性降序排列的。


六、员工分组案例

公司招聘了10个员工ABCDEFGHIJ,现在需要指派员工在那个部门工作,员工信息包括姓名和工资,部门分为策划、美术、研发。随机给10名员工分配部门和工资,通过multimap容器进行信息的插入,key表示部门编号,value表示员工,可以分部门显示员工信息。
实现步骤:创建10名员工,放到vector中;遍历vector容器,取出每个员工,进行随机分组;分组后,将员工部门编号作为key,具体员工作为value,放入到multimap容器中;分部门显示员工信息。
该案例的代码实现如下。

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <ctime>
using namespace std;

class Staff
{
public:
	Staff(string name,int wage)
	{
		this->name = name;
		this->wage = wage;
	}
	string name;
	int wage;
};

void createStaff(vector<Staff> &v)
{
	string nameSeed = "ABCDEFGHIJ";
	for(int i=0;i<10;i++)
	{
		string name = "员工";
		name += nameSeed[i];
		int wage = rand()%1000+3000;  //3000-3999
		Staff s(name,wage);
		v.push_back(s);
	}
}

void setGroup(vector<Staff> &v,multimap<int,Staff> &m)
{
	for(vector<Staff>::iterator i=v.begin();i!=v.end();i++)
	{
		int dep_num = rand()%3+1;   //1-3  1策划、2美术、3研发
		m.insert(make_pair(dep_num,*i));   //给员工分配部门
	}
}

void showInfo(multimap<int,Staff> &m)
{
	cout<<"--------策划部门--------"<<endl;
	multimap<int,Staff>::iterator pos = m.find(1);  //找到起始位置
	for(int i=0;i<m.count(1) && pos!=m.end();i++)  //数量
	{
		cout<<"姓名: "<<pos->second.name<<"  工资:"<<pos->second.wage<<endl;
		++pos;
	}
	cout<<"--------美术部门--------"<<endl;
	pos = m.find(2);
	for(int i=0;i<m.count(2) && pos!=m.end();i++)
	{
		cout<<"姓名: "<<pos->second.name<<"  工资:"<<pos->second.wage<<endl;
		++pos;
	}
	cout<<"--------研发部门--------"<<endl;
	pos = m.find(3);
	for(int i=0;i<m.count(3) && pos!=m.end();i++)
	{
		cout<<"姓名: "<<pos->second.name<<"  工资:"<<pos->second.wage<<endl;
		++pos;
	}
}

void printStaff(vector<Staff> &v)
{
	for(vector<Staff>::iterator i=v.begin();i!=v.end();i++)
	{
		cout<<"name : "<<i->name<<"  wage : "<<i->wage<<endl;
	}
}

int main()
{
	srand((unsigned int)time(NULL));  //加入随机数种子,保证生成数的随机性
	vector<Staff> v;  //创建vector容器
	createStaff(v);  //创建员工信息
	printStaff(v);
	multimap<int,Staff> m;  //创建multimap容器
	setGroup(v,m);  //员工分组
	showInfo(m);   //分组显示员工信息
	system("pause");
	return 0;
}

案例的运行结果如下图所示。
在这里插入图片描述


本文参考视频:
黑马程序员匠心之作|C++教程从0到1入门编程,学习编程不再难

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/436831.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

文献速递:深度学习疾病预后--临床级计算病理学使用基于整张切片图像的弱监督深度学习

Title 题目 Clinical-grade computational pathology using weakly supervised deep learning on whole slide images 临床级计算病理学使用基于整张切片图像的弱监督深度学习 01 文献速递介绍 The development of decision support systems for pathology and their deplo…

下载无水印抖音视频

在抖音看到某些视频想下载&#xff0c;却出现无法保存在本地【显示"作品暂时无法保存,链接已复制"】。或者下载的视频有水印。 而某些微信小程序下载可能需要付费或者有水印。其实我们可以直接使用电脑浏览器直接下载。 举个例子: 这是来自王道官方账号的一条视频链…

融合软硬件串流多媒体技术的远程控制方案

远程技术已经发展得有相当水平了&#xff0c;在远程办公&#xff0c;云游戏&#xff0c;云渲染等领域有相当多的应用场景&#xff0c;以向日葵&#xff0c;todesk rustdesk等优秀产品攻城略地&#xff0c;估值越来越高。占据了通用应用的方方面面。 但是细分市场&#xff0c;还…

【Simulink系列】——控制系统仿真基础

声明&#xff1a;本系列博客参考有关专业书籍&#xff0c;截图均为自己实操&#xff0c;仅供交流学习&#xff01; 一、控制系统基本概念 这里就不再介绍类似于开环系统、闭环系统等基本概念了&#xff01; 1、数学模型 控制系统的数学模型是指动态数学模型&#xff0c;大致…

开源文生图大模型Playground v2.5发布:超越SD、DALL·E 3和 Midjourney

前言 在AI技术迅速发展的今天&#xff0c;文生图模型成为了艺术创作、设计创新等领域的重要工具。Playground v2.5的发布&#xff0c;不仅在技术上取得了突破&#xff0c;更在开源文化的推广与实践上迈出了重要一步。 Huggingface模型下载&#xff1a;https://huggingface.co/…

【记录处理Vue项目中Video.js播放不了MP4视频Bug】

记录处理Vue项目中Video.js播放不了MP4视频Bug 一、项目场景&#xff1a;二、问题描述三、原因分析&#xff1a;四、解决方案&#xff1a; 一、项目场景&#xff1a; 在Vue项目中使用Video.js播放MP4视频。 二、问题描述 在项目中使用Video.js播放MP4视频。视频采集上来存在数…

使用java批量写入环境变量

环境需求 jdk版本&#xff1a;1.8 jna依赖&#xff1a; <dependency><groupId>net.java.dev.jna</groupId><artifactId>jna</artifactId><version>5.10.0</version></dependency><dependency><groupId>net.java.…

Java - Spring MVC 实现跨域资源 CORS 请求

据我所知道的是有三种方式&#xff1a;Tomcat 配置、拦截器设置响应头和使用 Spring MVC 4.2。 设置 Tomcat 这种方式就是引用别人封装好的两个 jar 包&#xff0c;配置一下web.xml就行了。我也并不推荐&#xff0c;这里放两个我在网上找到的配置相关文章&#xff0c;感兴趣可…

更快更强,Claude 3全面超越GPT4,能归纳15万单词

ChatGPT4和Gemini Ultra被Claude 3 AI模型超越了&#xff1f; 3月4日周一&#xff0c;人工智能公司Anthropic推出了Claude 3系列AI模型和新型聊天机器人&#xff0c;其中包括Opus、Sonnet和Haiku三种模型&#xff0c;该公司声称&#xff0c;这是迄今为止它们开发的最快速、最强…

【论文阅读】DeepLab:语义图像分割与深度卷积网络,自然卷积,和完全连接的crf

【论文阅读】DeepLab:语义图像分割与深度卷积网络&#xff0c;自然卷积&#xff0c;和完全连接的crf 文章目录 【论文阅读】DeepLab:语义图像分割与深度卷积网络&#xff0c;自然卷积&#xff0c;和完全连接的crf一、介绍二、联系工作三、方法3.1 整体结构3.2 使用空间金字塔池…

Stable Diffusion 提示词语法(Prompt)

本文收录于《AI绘画从入门到精通》专栏&#xff0c;专栏总目录&#xff1a;点这里。 大家好&#xff0c;我是水滴~~ 本篇文章主要讲述 Stable Diffusion 提示词语法&#xff0c;主要包括&#xff1a;提示词的概念、提示词的长度、权重、分步绘制、交替绘制、组合绘制等&#x…

ORA/GSA -- 学习记录

brief over-representation analysis(ORA),过表“达”分析&#xff0c;就是我们做多分组的RNAseq数据解析后会得到一些差异表达的gene&#xff0c;有些时候是单独拿出一个差异gene去解释表型&#xff0c;缺点是欠缺证据力度。有些人就把一些相关的差异gene放在一块儿解释&…

leetcode 热题 100_最大子数组和

题解一&#xff1a; 动态规划&#xff1a;这是一道经典的动态规划题。维护一个dp数组&#xff0c;dp[i]表示0~i组成的数组的最大子数组和。当数组长度为1时&#xff0c;最大和连续子数组是它本身&#xff0c;也就是dp[i]nums[i]。当数组长度每增加1时&#xff0c;最大和连续子数…

精准获客、优化体验,Xinstall数据自动分析全搞定

在移动互联网时代&#xff0c;App已经成为了我们生活中不可或缺的一部分。然而&#xff0c;对于App开发者来说&#xff0c;如何有效地评估渠道效果、精准获客以及优化用户体验&#xff0c;一直是一个令人头疼的问题。幸运的是&#xff0c;Xinstall作为一款一站式App全渠道统计服…

YOLOv9: Learning What You Want to Learn Using Programmable Gradient Information

paper: https://arxiv.org/abs/2402.13616 code YOLOv9: Learning What You Want to Learn Using Programmable Gradient Information 一、引言部分二、问题分析2.1 信息瓶颈原理2.2 可逆函数 三、本文方法3.1 可编程梯度信息 四、实验4.1消融实验部分 今天的深度学习方法关注的…

Ajax、Axios、Vue、Element与其案例

目录 一.Ajax 二.Axios 三.Vue 四.Element 五.增删改查案例 一.依赖&#xff1a;数据库&#xff0c;mybatis&#xff0c;servlet&#xff0c;json-对象转换器 二.资源&#xff1a;elementvueaxios 三.pojo 四.mapper.xml与mapper接口 五.service 六.servlet 七.html页…

产品展示型wordpress外贸网站模板

孕婴产品wordpress外贸网站模板 吸奶器、待产包、孕妇枕头、护理垫、纸尿裤、孕妇装、孕婴产品wordpress外贸网站模板。 https://www.jianzhanpress.com/?p4112 床品毛巾wordpress独立站模板 床单、被套、毛巾、抱枕、靠垫、围巾、布艺、枕头、乳胶枕、四件套、浴巾wordpre…

请说明Vue中的异步组件加载

Vue中的异步组件加载是指当页面需要渲染某个组件时&#xff0c;可以在需要时再去加载这个组件&#xff0c;而不是在页面初始化的时候就将所有组件一次性加载进来。这种方式能够有效降低页面的初始加载时间&#xff0c;提升用户体验。 在Vue中&#xff0c;我们可以使用import函…

Dgraph 入门教程三(linux本地部署)

上一章中&#xff0c;我们用的官方的Clound操作的&#xff0c;怎么在本地部署一套Dgraph呢。这一章将做详细介绍。安装有好几种方式&#xff0c;最简单的就是联网部署。因为项目需要&#xff0c;这里先不介绍和测试线上部署了&#xff0c;只介绍离线部署。 1、下载安装包 Rel…

flask 数据库迁移报错 Error: No such command ‘db‘.

初学FLASK&#xff0c;使用pycharm的terminal 启动&#xff0c;实现数据库迁移 文件结构 项目启动文件不在一级目录pycharm>terminal启动 由于自己初入 python flask 很多东西并不懂&#xff0c;只能依葫芦画瓢&#xff0c;使用如下命令,输入完第一行命令执行没有任何错误…