包含头文件<map>
映射代表的是一种关系,有点类似哈希结构(数据的一个抽象地址和这个元素的一个关系)
也可以把它叫做关联式容器
map<int, string> mapData; //创建一个map容器
map 里面存储的数据是一个数对类型
在 c++ 当中有一个数对类型的结构体,pair 类型:两种类型的模板类,把两个类型强制关联在一起,第一个 first,第二个 second,要用两个类型去做实例化
#include <map>
#include <iostream>
#include <graphics.h>
using namespace std;
//模板类 第一个类型 第二个类型
template <class _Ty1, class _Ty2>
struct MyPair
{
_Ty1 first;
_Ty2 second;
MyPair(_Ty1 first, _Ty2 second) :first(first), second(second) {}
};
void testPair()
{
//构建一个pair对象-> 两个类型的未知类型
//用 int 对应 string-> 对应关系
pair<int, string> pData(1, "string");
MyPair<int, string> myPData(1, "string");
//访问数据
cout << pData.first << " " << pData.second << endl;
}
int main()
{
testMap();
testUserData();
testmultimap();
return 0;
}
map 的创建与使用
自带排序,默认从小到大
数据唯一性(单映射可以避免出现重复现象)
map 有 3 种插入方式:
要把数据插入到 map 当中,一定是把数据构建成一个数对类型,才能插到 map 容器中
1.用 insert 函数做插入
2.用make_pair外部的(模板函数,需要传参)函数构建数对插入
3.单映射(自己独特的插入方式),可以直接采用数组下标的方式进行插入,map 相比数组来说,这个下标是没有任何要求(因为内部做了重载)
下标可以是负数,并且一般不好用 for 循环去做打印(由于下标可以没有规律,避免用 for 循环去做打印)
mapData[键] = 值;
mapData[-1] = string( "string - 1"(构建一个 string 类型的对象));
-1 是键(first),"string - 1" 是值 (second)
map[ first ] = second;就是 first 对应 second
数组在一定程度上来说可以算是一种映射
相同的键采用的是覆盖方式(如果存在相同的键,会保留最后一次插入的值),由于比较是根据键去比较的,和值没有关系(把第一个数据叫做键,第二个数据叫做值)
实际使用中更多是用键去存储一些东西:Easyx-----c++实现推箱子_小雪菜本菜的博客-CSDN博客_easyx推箱子
map<string, IMAGE*> img;
img["墙"] = new IMAGE; 直接用墙对应一个 IMAGE 类型的数据,使用的时候,直接用img["墙"]即可,img["墙"]等效于键的值
img["路"] = new IMAGE; 加载资源
putimage(0, 0, img["墙"]); 在某一个位置贴一张图片,直接使用 img["墙"]
putimage(0, 0, img["路"]);
music["开始"] = "./res/game_mudic.mp3"; 每一个音乐文件对应一个路径
Easyx-----c++实现飞机大战_小雪菜本菜的博客-CSDN博客_飞机大战掩码图
在做一些游戏的时候,这个游戏可能比较大,它里面有很多音乐文件,每一种音乐文件的操作方式可能不太一样。用 map 管理资源是极其合适的,因为我们可以直接去操作资源,存储图片也是一样的,map 可以存在任何对应关系,例如可以用 string 对应一个函数指针,可以用 string 对应一个图片资源. . .
在图形库中,可能会因为资源太多,分不清楚哪一个变量名表示哪一个资源,用 map 操作就可以避免这个尴尬的情况(使用 map,关联性比较强)
之前可能是数组去存储,数组的弊端就是下标是一个整数,可区分性太低,在写项目的时候可能写着写着就忘记某一个下标代表的是什么,用映射关系就不存在这种问题
map 的特性:可以通过键的方式去访问值,因为就是一个键对应一个值,用对象 + 下标的方式就是访问值
参数:数据类型、数据类型、比较准则、分配器
void testMap()
{
//传入两个未知类型做实例化-> 数对类型
map<int, string> mapData;
map<int, string, less<int>> mapData1; //和上面创建方式一样,从小到大
map<int, string, greater<int>> mapData2; //从大到小
//1.用insert函数做插入-> 要插入一个数对类型 需要把数据构建成pair类型的对象
mapData.insert(pair<int, string>(1, "string"));
//2.make_pair构建数对插入
mapData.insert(make_pair<int, string>(3, "string3"));
//3.单映射,可以直接采用数组下标的方式进行插入
mapData[-1] = string("string-1"); //等效插入一个数对类型
//上面代码等效: mapData.insert(pair<int,string>(-1,"string-1"))
mapData[1] = "string1"; //相同键 采用的是覆盖方式
//迭代器遍历
for (auto iter = mapData.begin(); iter != mapData.end(); iter++)
{
//*iter指的是pair类型-> 先打印它里面的键 再打印它里面的值
cout << iter->first << " " << iter->second<<endl;
}
for (auto v : mapData)
{
cout << v.first << "\t" << v.second << endl;
}
//通过键的方式去访问值
cout << mapData[1] << endl; //用的时候直接使用即可
//用erase函数去做删除-> 通过键去做删除 传入键 删除1这个位置
mapData.erase(1);
for (auto v : mapData)
{
//v是一个结构体用.的方式访问
cout << v.first << "\t" << v.second << endl;
}
cout << endl;
}
/* 输出 */
-1 string-1
1 string1
3 string3
-1 string-1
1 string1
3 string3
string1
/* 1 string1 被删除了 */
-1 string-1
3 string3
map 存储自定义类型数据
做一个匹配,一个 MM 对应一个 Boy
map 中可以任何关系相对应,只要你觉得它们之间可以形成关联
需要重载,由于整个 map 的排序是采用 MM 去排序的,MM 有两个属性,可以通过 name 的方式去排序(按照什么方式比较可以随便写),就需要重载
不是说随便重载一个,Boy 是没有排序效果的,只有键才有排序效果,所以应该是重载键里面的比较(不是说把重载随便写到哪个类里面都可以)
//MM类
class MM
{
public:
MM() = default;
MM(string name, int age) :name(name), age(age) {}
void print() const /* 对象含有与成员函数"MM::print"不兼容的类型限定符 对象类型是: const MM */
{
cout << name << "\t" << age << endl;
}
//按照姓名的方式比较
bool operator<(const MM& object)const
{
return this->name < object.name;
}
protected:
string name;
int age;
};
//Boy类
class Boy
{
public:
Boy() = default; /* "Boy::Boy" 没有合适的默认构造函数可用 */
Boy(string name, int age) :name(name), age(age) {}
void print() const
{
cout << name << "\t" << age << endl;
}
protected:
string name;
int age;
};
void testUserData()
{
//用MM对应Boy
map<MM, Boy> mbData;
//下标法使用
//MM对象这个键对应一个值-> 对应一个Boy对象
mbData[MM("小美", 19)] = Boy("小张", 29);
//打印Boy的信息 mbData[MM("小美", 19)]等效Boy对象-> Boy对象调用成员函数print是没有什么问题的
mbData[MM("小美", 19)].print();
//只要类型上对应都可以采用下标法去访问
mbData[MM("小丽", 20)] = Boy("小明", 18);
//打印所有的信息
cout << "配对信息:" << endl;
for (auto v : mbData)
{
//容器管理自定义类型数据
//v代表数对类型:pair<MM,Boy> v是常属性的
//v.frist:MM对象 应该调用成员函数去做打印
//v.second:Boy对象
v.first.print();
v.second.print();
}
}
/* 输出 */
小张 29
配对信息:
小丽 20
小明 18
小美 19
小张 29
多重映射
多重映射,没有什么限制,什么样对应关系都可以插入到这个映射容器中。只有单纯的排序功能
多重映射的弊端:因为存在相同的键,所以不能采用下标法插入(由于存在相同的键,所以在用下标法访问的时候,分不清楚把值插到哪个键里面去了)
void testmultimap()
{
multimap<int, string> mulData;
//其他操作一样
mulData.insert(pair<int, string>(1, "string"));
mulData.insert(pair<int, string>(1, "string1"));
mulData.insert(pair<int, string>(2, "string"));
mulData.insert(pair<int, string>(3, "string"));
mulData.insert(make_pair<int, string>(3, "string"));
//遍历
for (auto v : mulData)
{
cout << v.first << "\t" << v.second << endl;
}
}
/* 输出 */
/* 所有的关系都会保留下来:两个1对应string */
1 string
1 string1
2 string
3 string
3 string