从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);   //移除容器中所有的6printList(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 sidereturn (_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} valuereturn (_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-3999Staff 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入门编程,学习编程不再难

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

边缘计算基础知识

目录 边缘计算简介任务卸载简介边缘存储系统 边缘计算简介 边缘计算是指利用靠近数据生成的网络边缘侧的设备&#xff08;如移动设备、基站、边缘服务器、边缘云等&#xff09;的计算能力和存储能力&#xff0c;使得数据和任务能够就近得到处理和执行。 一个典型的边缘计算系…

泽众云真机-为什么老机型专区大部分是维护中?如何解决

最近&#xff0c;泽众云真机平台有几位用户向我们咨询&#xff0c;为什么老机型专区大部分是维护中&#xff1f;我想使用这些机型怎么办&#xff1f; 首先来解释一下&#xff0c;为什么叫“老机型专区”&#xff1f;因为一些老的机型之前一直是在线状态&#xff0c;通过我们长期…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:Checkbox)

提供多选框组件&#xff0c;通常用于某选项的打开或关闭。 说明&#xff1a; API version 11开始&#xff0c;Checkbox默认样式由圆角方形变为圆形。 该组件从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 无 接口…

Hello C++ (c++是什么/c++怎么学/c++推荐书籍)

引言 其实C基础语法基本上已经学完&#xff0c;早就想开始写C的博客了&#xff0c;却因为其他各种事情一直没开始。原计划是想讲Linux系统虚拟机安装的&#xff0c;后来考虑了一下还是算了&#xff0c;等Linux学到一定程度再开始相关博客的写作和发表吧。今天写博客想给C开个头…

解决:ModuleNotFoundError: No module named ‘paddle‘

错误显示&#xff1a; 原因&#xff1a; 环境中没有‘paddle’的python模块&#xff0c;但是您在尝试导入 解决方法&#xff1a; 1.普通方式安装&#xff1a; pip install paddlepaddle #安装命令 2.镜像源安装 pip install paddlepaddle -i https://pypi.tuna.tsinghua.e…

饮料换购 刷题笔记

直接开个计数器mask 每当饮料现存数-1&#xff1b; cnt;且mask; 一旦mask达到3 饮料现存数 计数器清零3 代码 #include <iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; int main(){ int n; …

【论文整理】自动驾驶场景中Collaborative Methods多智能体协同感知文章创新点整理

Collaborative Methods F-CooperV2VNetWhen2commDiscoNetAttFusionV2X-ViTCRCNetCoBERTWhere2commDouble-MCoCa3D 这篇文章主要想整理一下&#xff0c;根据时间顺序这些文章是怎么说明自己的创新点的&#xff0c;又是怎么说明自己的文章比别的文章优越的。显然似乎很多文章只是…

网络编程:数据库实现增删改

1.数据库实现增删改 程序代码&#xff1a; 1 #include<myhead.h>2 //定义添加数据函数3 int do_add(sqlite3*ppDb)4 {5 //准备sql语句6 int add_numb;//工号7 char add_name[20];//姓名8 double add_salary;9 printf("请输入要添加的工号:&quo…

18-Java迭代器模式 ( Iterator Pattern )

Java迭代器模式 摘要实现范例 迭代器模式&#xff08;Iterator Pattern&#xff09;用于顺序访问集合对象的元素&#xff0c;不需要知道集合对象的底层表示 迭代器模式是 Java 和 .Net 编程环境中非常常用的设计模式 迭代器模式属于行为型模式 摘要 1. 意图 提供一种方法…

sql server使用逗号,分隔保存多个id的一些查询保存

方案一&#xff0c;前后不附加逗号&#xff1a; 方案二&#xff0c;前后附加逗号&#xff1a; 其他保存方案&#xff1a; &#xff08;这里是我做一个程序的商家日期规则搞得&#xff0c;后面再补具体操作&#xff09;&#xff1a; 1,2,3 | 1,2,3 | 1,2,3; 1,2,3 &#xff1…

Unity性能优化篇(十二) 音频优化之导入音频后的属性设置

Unity支持后缀为.wav、.ogg、.mp3的音频文件&#xff0c;但建议使用.wav&#xff0c;因为Unity对它的支持特别好。 注意&#xff1a;Unity在构建项目时总是会自动重新压缩音频文件&#xff0c;因此无需刻意提前压缩一个音频文件再导入Unity&#xff0c;因为这样只会降低该音频文…

wsl 安装 ubuntu

文章目录 打开Windows PowerShell查看可安装的ubuntu安装相对应的ubuntu将用户添加到sudoers文件中&#xff0c;并赋予了该用户sudo权限。 打开Windows PowerShell 以管理员的身份运行 查看可安装的ubuntu wsl.exe --list --online安装相对应的ubuntu wsl --install 版本…

【云服务】-云服务 的基础

企业IT架构的演进历史 云计算的定义 云计算是一种模型&#xff0c;可以实现随时随地便携地可配置资源共享池中所需的资源&#xff08;例如&#xff0c;网络、服务器、存储、应用及服务&#xff09;。资源能快速供应并且释放&#xff0c;使管理资源的工作量和与服务提供商的交…

中小企业应该如何应用人才测评系统

人才测评系统应用场景越来越多&#xff0c;很多企业也开始通过人才测评系统&#xff0c;来对员工的性格特点和岗位进行评估&#xff0c;比如作为项目经理的我&#xff0c;总是想先从员工内部选拔领导者&#xff0c;然而这就有很大的难度&#xff0c;那么团队建设之初&#xff0…

Python小白福利之enumerate函数

enumerate函数用于遍历序列中的元素以及它们的下标。 enumerate函数说明&#xff1a; 函数原型&#xff1a;enumerate(sequence, [start0]) 功能&#xff1a;将可循环序列sequence以start开始分别列出序列数据和数据下标 即对一个可遍历的数据对象(如列表、元组或字符串)&a…

protobufjs使用教程,支持proto文件打包成typescript或javascript脚本

官方链接&#xff1a;https://docs.cocos.com/creator/manual/zh/scripting/modules/example.html 第一步&#xff0c;安装nodejs。&#xff08;自行安装&#xff09; 安装教程可参考 https://www.runoob.com/nodejs/nodejs-install-setup.html 第二步&#xff0c;创建cocos…

AD导入FreeCAD生成的step文件后颜色丢失?

最近在绘制一个模组&#xff0c;本身是想在网上找是否有类似的3D模型&#xff0c;但是似乎没有&#xff0c;此时我就自己用FreeCAD画了一个&#xff0c;但是在导入到AD中就出现了问题 使用freecad画出的模型样式&#xff1a; 导入到AD中去后的样式&#xff1a; freecad中导出时…

passwd: Authentication token manipulation error

passwd: Authentication token manipulation error 身份验证令牌操作错误。 可能原因&#xff1a; 1、密码文件无修改权限&#xff08;有i权限&#xff09; lsattr /etc/{passwd,shadow} 取消方法 chattr -i /etc/passwd chattr -i /etc/passwd 2、/文件系统无空间或者无inod…

GOWIN软件使用

1、管脚复用 根据自己需求把复用管脚勾选上&#xff0c;管脚当普通管脚使用 JTAG设置成普通管脚&#xff0c;下载程序时候JTAGEN管脚需要上拉高电平&#xff08;可以在下载器线上上拉个电阻&#xff0c;下载后把下载线拔走&#xff0c;否则JTAG管脚无法使用&#xff0c;管脚充…

Linux - 反弹Shell

概念 Shell 估计大家都不陌生&#xff0c;简单来说&#xff0c;就是实现用户命令的接口&#xff0c;通过这个接口我们就能实现对计算机的控制&#xff0c;比如我们常见的 ssh 就是执行的 Shell 命令实现对远程对服务器的控制。 那反弹 Shell &#xff08; Reverse Shell&…