文章目录
- 一、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入门编程,学习编程不再难