map容器
map容器原理图
map容器和multiset容器一样,元素都是对组pair,map容器不允许存在两个相同的键值的元素
map容器的迭代器也是只读迭代器。
map容器API
#include <iostream>
#include <map>
using namespace std;
/*
* map构造函数
* map<T1,T2> map1;//默认构造函数
* map(const map &map1);//默认拷贝构造函数
*
* map容器赋值操作
* map &operator=(const map &map);//重载等号运算符拷贝
* swap(map1);//交换函数
*
* map容器大小操作
* size();//返回容器元素的数目
* empty();//判断容器是否为空
*
* map容器数据存取操作
* map.insert(pair(键值,实值));//map容器元素都是对组,插入成功返回pair<iterator,bool>;
* map<int,string> map1;
* map1.insert(pair<int,string>(1,"张三"));
* map1.insert(make_pair(2,"李四"));
* map1.insert(map<int,string>::value_type(3,"张三丰"));
* map1[4]="小王";
* map容器的删除操作
* map1.clear();//清空所有元素
* erase(position);//删除position所指的元素,返回下一个元素的迭代器
* erase(begin,end);//删除区间[begin,end)的所有元素
* erase(keypair);//删除key为keypair的对组
* map容器的查找操作
* find(key);//查找key是否存在,若存在返回该key的元素的迭代器,不存在返回该容器最后一个迭代器即map1.end();
* count(keyElement);//返回容器中key为keyElement的对组个数,注意因为map容器的特殊性,count返回的个数要么为0,要么为1
* 而multimap则可能会返回>1
* lower_bound(keyElement);//返回第一个key>=keyElement的元素的迭代器
* upper_bound(keyElement);//返回第一个key>keyElement的元素的迭代器
* equal_range(keyElement);//返回容器中key与keyElement相等的上下限的两个迭代器
*/
//自定义map容器遍历算法
void printMap1(map<int,string> &map1){
map<int,string>::const_iterator it=map1.begin();
for(;it!=map1.end();it++){
//*it==pair<int,string>;注意这里的*it是map容器的元素(pair)
cout<<(*it).first<<" "<<(*it).second<<endl;
}
}
void test(){
map<int,string> map1;
map1.insert(pair<int,string>(10086,"中国移动"));
map1.insert(make_pair(10000,"中国电信"));
map1.insert(map<int,string>::value_type(10010,"中国联通"));
map1[9527]="星爷";
//注意map容器key不可以重复且要存在
cout<<map1[1008]<<endl;
cout<<map1.count(10086)<<endl;
printMap1(map1);
}
int main()
{
test();
return 0;
}
输出结果:
通过上下文顺序和输出结果对比,发现数组形式优先遍历,之后是make_pair,map<int,string>::value_type();最后是pair<int,string>,模板的调用有先后顺序,但是数组容器发生数组下标访问越界导致程序出现异常,因此建议优先使用make_pair。
map的实值为类的应用 (less比较)
#include <iostream>
#include <map>
using namespace std;
/*
* map构造函数
* map<T1,T2> map1;//默认构造函数
* map(const map &map1);//默认拷贝构造函数
*
* map容器赋值操作
* map &operator=(const map &map);//重载等号运算符拷贝
* swap(map1);//交换函数
*
* map容器大小操作
* size();//返回容器元素的数目
* empty();//判断容器是否为空
*
* map容器数据存取操作
* map.insert(pair(键值,实值));//map容器元素都是对组,插入成功返回pair<iterator,bool>;
* map<int,string> map1;
* map1.insert(pair<int,string>(1,"张三"));
* map1.insert(make_pair(2,"李四"));
* map1.insert(map<int,string>::value_type(3,"张三丰"));
* map1[4]="小王";
* map容器的删除操作
* map1.clear();//清空所有元素
* erase(position);//删除position所指的元素,返回下一个元素的迭代器
* erase(begin,end);//删除区间[begin,end)的所有元素
* erase(keypair);//删除key为keypair的对组
* map容器的查找操作
* find(key);//查找key是否存在,若存在返回该key的元素的迭代器,不存在返回该容器最后一个迭代器即map1.end();
* count(keyElement);//返回容器中key为keyElement的对组个数,注意因为map容器的特殊性,count返回的个数要么为0,要么为1
* 而multimap则可能会返回>1
* lower_bound(keyElement);//返回第一个key>=keyElement的元素的迭代器
* upper_bound(keyElement);//返回第一个key>keyElement的元素的迭代器
* equal_range(keyElement);//返回容器中key与keyElement相等的上下限的两个迭代器
*/
//自定义map容器遍历算法
void printMap1(map<int,string> &map1){
map<int,string>::const_iterator it=map1.begin();
for(;it!=map1.end();it++){
//*it==pair<int,string>;注意这里的*it是map容器的元素(pair)
cout<<(*it).first<<" "<<(*it).second<<endl;
}
}
class Person
{
friend void printMap2(map<int,Person,less<int>> &map2);
public:
Person() {}
Person(int num,string name,double score){
this->name=name;
this->num=num;
this->score=score;
}
private:
int num;
string name;
double score;
};
void printMap2(map<int,Person,less<int>> &map2){
map<int,Person,less<int>>::const_iterator it1=map2.begin();
for(;it1!=map2.end();it1++){
cout<<(*it1).first<<" "<<(*it1).second.name<<" "<<(*it1).second.num<<" "<<(*it1).second.score<<endl;
}
}
void test(){
map<int,string> map1;
map1.insert(pair<int,string>(10086,"中国移动"));
map1.insert(make_pair(10000,"中国电信"));
map1.insert(map<int,string>::value_type(10010,"中国联通"));
map1[9527]="星爷";
//注意map容器key不可以重复且要存在
cout<<map1[1008]<<endl;
cout<<map1.count(10086)<<endl;
printMap1(map1);
}
void test1(){
map<int,Person,less<int>> map2;
map2.insert(make_pair(100,Person(100,"Lucy",99.99)));
map2.insert(pair<int,Person>(200,Person(200,"Duck",99.88)));
map2.insert(map<int,Person,less<int>>::value_type(300,Person(300,"Juck",99.98)));
map2[101]=Person(101,"快乐崇拜",99.887);
//cout<<map2[102]<<endl;
cout<<map2.count(101)<<endl;
printMap2(map2);
}
int main()
{
test1();
return 0;
}
输出结果:
通过比较器less<T>可以对元素进行排序,该方法可以实现类的数据操作,需要注意的是如果键值对应的实值不存在会报错,比如如上数据使用数组方法操作会报如下错误:
D:\study\STL\map\main.cpp:89: error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'std::map<int, Person, std::less<int> >::mapped_type {aka Person}')
cout<<map2[102]<<endl;
^
map的实值为类的应用 (greater比较)
#include <iostream>
#include <map>
using namespace std;
/*
* map构造函数
* map<T1,T2> map1;//默认构造函数
* map(const map &map1);//默认拷贝构造函数
*
* map容器赋值操作
* map &operator=(const map &map);//重载等号运算符拷贝
* swap(map1);//交换函数
*
* map容器大小操作
* size();//返回容器元素的数目
* empty();//判断容器是否为空
*
* map容器数据存取操作
* map.insert(pair(键值,实值));//map容器元素都是对组,插入成功返回pair<iterator,bool>;
* map<int,string> map1;
* map1.insert(pair<int,string>(1,"张三"));
* map1.insert(make_pair(2,"李四"));
* map1.insert(map<int,string>::value_type(3,"张三丰"));
* map1[4]="小王";
* map容器的删除操作
* map1.clear();//清空所有元素
* erase(position);//删除position所指的元素,返回下一个元素的迭代器
* erase(begin,end);//删除区间[begin,end)的所有元素
* erase(keypair);//删除key为keypair的对组
* map容器的查找操作
* find(key);//查找key是否存在,若存在返回该key的元素的迭代器,不存在返回该容器最后一个迭代器即map1.end();
* count(keyElement);//返回容器中key为keyElement的对组个数,注意因为map容器的特殊性,count返回的个数要么为0,要么为1
* 而multimap则可能会返回>1
* lower_bound(keyElement);//返回第一个key>=keyElement的元素的迭代器
* upper_bound(keyElement);//返回第一个key>keyElement的元素的迭代器
* equal_range(keyElement);//返回容器中key与keyElement相等的上下限的两个迭代器
*/
//自定义map容器遍历算法
void printMap1(map<int,string> &map1){
map<int,string>::const_iterator it=map1.begin();
for(;it!=map1.end();it++){
//*it==pair<int,string>;注意这里的*it是map容器的元素(pair)
cout<<(*it).first<<" "<<(*it).second<<endl;
}
}
class Person
{
friend void printMap2(map<int,Person,greater<int>> &map2);
public:
Person() {}
Person(int num,string name,double score){
this->name=name;
this->num=num;
this->score=score;
}
private:
int num;
string name;
double score;
};
void printMap2(map<int,Person,greater<int>> &map2){
map<int,Person,greater<int>>::const_iterator it1=map2.begin();
for(;it1!=map2.end();it1++){
cout<<(*it1).first<<" "<<(*it1).second.name<<" "<<(*it1).second.num<<" "<<(*it1).second.score<<endl;
}
}
void test(){
map<int,string> map1;
map1.insert(pair<int,string>(10086,"中国移动"));
map1.insert(make_pair(10000,"中国电信"));
map1.insert(map<int,string>::value_type(10010,"中国联通"));
map1[9527]="星爷";
//注意map容器key不可以重复且要存在
cout<<map1[1008]<<endl;
cout<<map1.count(10086)<<endl;
printMap1(map1);
}
void test1(){
map<int,Person,greater<int>> map2;
map2.insert(make_pair(100,Person(100,"Lucy",99.99)));
map2.insert(pair<int,Person>(200,Person(200,"Duck",99.88)));
map2.insert(map<int,Person,greater<int>>::value_type(300,Person(300,"Juck",99.98)));
map2[101]=Person(101,"快乐崇拜",99.887);
//cout<<map2[102]<<endl;
cout<<map2.count(101)<<endl;
printMap2(map2);
}
int main()
{
test1();
return 0;
}
输出结果:
multimap容器
multimap容器同map容器类似,为了解决map容器键值不能重复的问题,multimap容器应运而生。
multimap容器与map容器的唯一区别就在于multimap容器允许键值重复
multimap容器原理图
multimap容器 API
#include <iostream>
#include<map>
#include<vector>
#include<time.h>
#include<stdlib.h>
using namespace std;
/*案例:公司HR新招聘了五位新员工,5位员工进入公司后,需要分派到各个部门相应岗位上工作,HR需要录入5位员工的信息,相关信息有:姓名
* 年龄、电话、工号、部门、工资、部门领导等信息
*/
class worker
{
friend void inputWorker(vector<worker> &w);
friend void workerJoinDepartment(vector<worker> &w,multimap<int,worker> &m);
friend void showWorkerAndDepartment(multimap<int,worker> &m);
public:
worker() {}
worker(string name,int age,int telephone,int num,double money,string leader){
this->name=name;
this->age=age;
this->leader=leader;
this->money=money;
this->num=num;
this->telephone=telephone;
}
private:
string name;
int age;
int telephone;
int num;
double money;
string leader;
};
void inputWorker(vector<worker> &w){
srand(time(NULL));
string nameTemp="ABCDE";
int i=0;
for(;i<5;i++){
string name="员工";
name+=nameTemp[i];
int age=rand()%11+20;
int telephone=rand();
int num=rand()%100+101;
double money=rand()%10001+50000;
string leader="领导";
leader+=nameTemp[i];
w.push_back(worker(name,age,telephone,num,money,leader));
}
}
void workerJoinDepartment(vector<worker> &w,multimap<int,worker> &m){
//员工逐个分批加入各个部门
vector<worker>::iterator it=w.begin();
for(;it!=w.end();it++){
cout<<"请输入"<<(*it).name<<"加入部门(1:销售,2:研发,3:财务):";
int ob=0;
cin>>ob;
m.insert(make_pair(ob,*it));
}
}
void showWorkerAndDepartment(multimap<int,worker> &m){
cout<<"请输入需要显示的部门(1:销售,2:研发,3:财务):";
int ob=0;
cin>>ob;
switch (ob) {
case 1:
cout<<"--------------销售部门员工-------------"<<endl;
break;
case 2:
cout<<"--------------研发部门员工-------------"<<endl;
break;
case 3:
cout<<"--------------财务部门员工-------------"<<endl;
break;
default:
cout<<"输入的部门有误"<<endl;
break;
}
multimap<int,worker>::const_iterator it2;
it2=m.find(ob);
if(it2!=m.end()){
int n=m.count(ob);
int i=0;
for(;i<n;i++,it2++){
cout<<"\t"<<(*it2).second.name<<" "<<(*it2).second.age<<" "<<(*it2).second.telephone<<" "<<(*it2).second.\
num<<" "<<(*it2).second.money<<" "<<(*it2).second.leader<<endl;
}
}
}
void test(){
vector<worker> w;
inputWorker(w);
multimap<int,worker> m;
workerJoinDepartment(w,m);
showWorkerAndDepartment(m);
}
int main()
{
test();
return 0;
}
输出结果:
遇到cin>>不继续(bug解决办法)
tips:输入int数据的时候,差点给我整懵了,我发现使用qt自带的终端输出,一直让我输入,我一度怀疑自己的代码有问题了,仔细检查最后发现是qt 工具自带不识别
如果遇到这种情况,建议使用terminal
操作方法:左边一栏找到项目
勾选Run in terminal,(已经勾选了,也再勾选下,可能会失效所以再勾选下)
然后运行的时候就会显示terminal
unordered_map容器
与map容器、multimap容器不同,这种容器的底层实现他是基于哈希表的一种无序容器
这三种容器的区别:
有序性:
std::map
和std::multimap
是有序容器,按照键的顺序进行排序。std::map
中每个键只能对应一个值,如果插入已存在的键,则会替换旧值。std::multimap
中的键可以对应多个值,可以插入多个相同的键。底层实现:
std::map
是基于红黑树(一种自平衡的二叉搜索树)实现的有序容器,使用二叉搜索树的性质保证有序性。std::multimap
也是基于红黑树实现,但允许插入相同的键。std::unordered_map
是基于哈希表实现的无序容器,使用哈希函数将键映射到桶中,实现快速的插入、查找和删除操作。查找效率:
std::map
和std::multimap
通过红黑树实现,每次查找的时间复杂度为 O(log n),其中 n 是容器中的元素数量。在有序情况下,可以使用二分查找进行范围查询。std::unordered_map
通过哈希表实现,平均情况下查找的时间复杂度为 O(1),最坏情况下可能达到 O(n)。由于哈希表的散列过程,无法进行范围查询。插入和删除效率:
std::map
和std::multimap
在插入和删除操作时需要维护红黑树的平衡性,时间复杂度为 O(log n)。std::unordered_map
的插入和删除操作在平均情况下时间复杂度为 O(1),最坏情况下可能达到 O(n)。内存占用:由于有序性的需要,
std::map
和std::multimap
在保存元素时需要额外存储红黑树的结构信息,因此相对占用的内存较多。而std::unordered_map
的存储结构相对简单,占用的内存较少。迭代器稳定性:对于
std::map
和std::multimap
,插入和删除元素不会导致迭代器失效,因为红黑树是自平衡的。但对于std::unordered_map
,插入和删除可能引发哈希表的重组,导致迭代器失效。因此,在使用迭代器时需要格外小心。选择合适的关联容器取决于实际的需求,如果需要有序存储并进行范围查询,则可以选择
std::map
或std::multimap
。如果不需要特定的顺序,且对查找性能有更高的要求,则可以选择std::unordered_map
。同时要考虑到内存占用和迭代器稳定性的要求
unordered_map API(0)
#include <iostream>
#include<unordered_map>
using namespace std;
struct Student{
std::string name;
int age;
std::string major;
};
int main()
{
unordered_map<int,Student> student;
student[1]={"Alice",21,"Computer Science"};
student[2]={"Bob",20,"Physics"};
student[3]={"Lucy",22,"Mathematics"};
int studentID=0;
cout<<"请输入要查找的学生ID:";
cin>>studentID;
if(student.find(studentID)!=student.end()){
cout<<"通过ID找到该学生"<<endl;
cout<<"Name:"<<student[studentID].name<<" "<<student[studentID].age<<\
" "<<student[studentID].major<<endl;
}else{
cout<<"通过ID未找到该学生"<<endl;
}
return 0;
}
输出结果:
unordered_map API(1)
#include <iostream>
#include<unordered_map>
#include<sstream>
using namespace std;
struct Student{
std::string name;
int age;
std::string major;
};
void test(){
unordered_map<string,int> wordCount;
string sentence="I love to code and I love to learn,but I do not love Nerve-racking.";
istringstream iss(sentence);
string word;
while (iss>>word) {
wordCount[word]++;
}
for(const auto& pair:wordCount){
cout<<pair.first<<": "<<pair.second<<endl;
}
}
void test1(){
unordered_map<int,Student> student;
student[1]={"Alice",21,"Computer Science"};
student[2]={"Bob",20,"Physics"};
student[3]={"Lucy",22,"Mathematics"};
int studentID=0;
cout<<"请输入要查找的学生ID:";
cin>>studentID;
if(student.find(studentID)!=student.end()){
cout<<"通过ID找到该学生"<<endl;
cout<<"Name:"<<student[studentID].name<<" "<<student[studentID].age<<\
" "<<student[studentID].major<<endl;
}else{
cout<<"通过ID未找到该学生"<<endl;
}
}
int main()
{
test();
return 0;
}
输出结果:
tips:这里使用了istringstream类,该类能把字符串切割为一系列的子字符串,然后通过>>输入给word,通过while循环,如果string相同则加1,同时将数据存储到unordered_map容器中,直到iss为NULL,则while循环结束。