amp和set

1.map和set是两个主要的关联容器。
2.关联容器和顺序容器的区别:
(1)关联容器中的元素是按照关键字来保存和访问的;
(2)顺序容器中的元素是按照它们在容器中的位置来顺序保存和访问的。 
3.map和set的底层都是通过红黑树来实现的,即中序遍历得到的序列是关键字的升序排列。
一.set 
(1)
容器中只含有关键字,并且关键字不可以重复。

通过以下代码,让我们来具体了解set怎么使用,以及了解set中一些函数的作用,参数以及返回值。

void PrintSet(set<int>& s)
{
    set<int>::iterator iteSet = s.begin();
    while(iteSet != s.end())//通过迭代器打印map关键字
    {
        cout<<*iteSet<<" ";
        ++iteSet;
    }
    cout<<endl;
}

void TestSet()
{
    set<int> setName;
    setName.insert(2);
    setName.insert(5);
    setName.insert(7);
    setName.insert(8);
    setName.insert(6);

    PrintSet(setName);

    cout<<setName.count(10)<<endl;//count()寻找关键字,如果给定的值存在,返回1;不存在,返回0

    setName.erase(6);//删除关键字6
    if(setName.find(6) == setName.end())
    {
        cout<<"12不存在"<<endl;
    }
    PrintSet(setName);//删除以后再次打印
}
(2)
我们知道,顺序容器支持下标操作,set和顺序容器不同,set不支持下标操作. 
1)find函数:如果要找到的关键字存在,返回指向该关键字的迭代器;如果不存在,返回容器中最后一个元素的下一个位置。 
2)set的关键字是const类型的,因此,set的关键字是不可以改变的,只能读不能写,但是根据编译器的不同,也会有所不同
按照顺序打印的结果都是按照关键字升序排列的,那么如何使得打印出的结果是降序的,我们有几种方法:仿函数;反向迭代器。
以下给出用反向迭代器让打印结果降序排列(其实用法和前面的一模一样):

void ReversePrintSet(set<int> s)//用反向迭代器让打印结果降序排列
{
	set<int>::reverse_iterator reIte = s.rbegin();
	while(reIte != s.rend())
	{
		cout<<*reIte<<" ";
		++reIte;
	}
	cout<<endl;
}
二:map
(1)map 
map和set有一点区别,set中只存关键字,而map中存储的不仅仅是关键字,还存在关键字所对应的值。
也就是我们之前学过的key-value类型。
所以map中的每一个元素都是pair类型。
pair是一个结构体,pair里边有两个成员:①K类型的first;②V类型的second。
创建pair类型的对象有以下几种方法:
①pair<string,int>("苹果",1);
②make_pair("橘子",2);
③pair<string,int> p = {"香蕉",3};
在以下的代码中我通一用第一种方法------①pair<string,int>("苹果",1);
(2)下面我们通过代码来学习如何使用map中的函数
void TestMap()
{
	map<string,int> mapName;//创建一个map对象mapName,里面的每个元素都是pair<string,int>类型
	//插入元素
	mapName.insert(pair<string,int>("苹果",1));
	mapName.insert(pair<string,int>("香蕉",3));
	mapName.insert(pair<string,int>("西瓜",2));
	mapName.insert(pair<string,int>("橘子",4));

	PrintMap(mapName);//打印map中的元素
	//查找
	map<string,int> ::iterator ite1;//定义迭代器ite1
	ite1 = mapName.find(string("苹果"));//寻找苹果
	if(ite1 != mapName.end())
		cout<<"苹果被找到"<<endl;
	ite1 = mapName.find(string("西瓜"));//寻找西瓜
	if(ite1 == mapName.end())
		cout<<"西瓜没有找到"<<endl;

	//修改某个关键字key的值value
	map<string,int> ::iterator ite2;//定义迭代器ite2
	ite2 = mapName.find(string("橘子"));//先寻找橘子
	if(ite2 != mapName.end())//如果寻找到了
	{
		ite2->second = 5;//将橘子改成5号
	}
	PrintMap(mapName);//再次打印map中的元素
	ReversePrintMap(mapName);//反向打印}

void PrintMap(const map<string,int>& m)//正常打印---升序
{
	map<string,int>::const_iterator iteMap = m.begin();//因为传进来m是const,所以迭代器也要用const类型的
	while(iteMap != m.end())
	{
		cout<<(*iteMap).first<<":"<<(*iteMap).second<<endl;
		++iteMap;
	}
	cout<<endl;
}

void ReversePrintMap(map<string,int> m)//使用反向迭代器使打印结果变成降序
{
	map<string,int>::reverse_iterator reIte = m.rbegin();
	while(reIte != m.rend())
	{
		cout<<reIte->first<<":"<<reIte->second<<endl;
		++reIte;
	}
	cout<<endl;
}
(3)map的应用
①map经常被用在很多方面。比如:
●统计一篇文章中单词出现的次数,
●统计班级同学喜欢吃的水果以及喜欢该水果的人数等等。
下面给出统计吃水果的例子的实现代码:
//统计班级学生喜欢吃的水果
①▼
void CountFavoriteFruits_1(vector<string> v)
{
	map<string ,int> countMap;
	for(size_t i = 0; i < v.size(); ++i)
	{
		map<string,int>::iterator ret = countMap.find(v[i]);//先查找v[i]是否已经存在
		if(ret != countMap.end())//已经存在
		{
			ret->second++;
		}
		else//没有存在,进行插入
		{
			countMap.insert(pair<string,int>(v[i],1));
		}
	}
}

这种方法是可以统计出结果的,但是整个过程会遍历map两次(find遍历一次,insert遍历一次)。
先查找,如果原来已经存在,那么给对应的second加1即可,如果不存在,将其插入。

②▼

void CountFavoriteFruits_2(vector<string> v)
{
	map<string,int> countMap;
	for(size_t i = 0; i< v.size(); ++i)
	{
		//insert()的实现原理:如果存在,则返回要插入元素所在的位置,以及false;如果不存在,则进行插入
		pair<map<string,int>::iterator,bool> ret = countMap.insert(pair<string,int>(v[i],1));
		if(ret.second == false)//表明没有插入成功
		{
			ret.first->second ++;
		}
	}
}

这种方法中 ,我们巧用insert的返回值,●如果不存在,插入,返回指向插入位置的迭代器以及true;
●如果存在,返回指向已经存在位置的迭代器 和flase,然后将其对应second加1即可。

③▼

void CountFavoriteFruits_3(vector<string> v)
{
	map<string,int> countMap;
	for(size_t i = 0; i < v.size(); ++i)
	{
		//operator[],没有则进行插入,有则返回value的引用
		countMap[v[i]]++;
	}
	SelectTop3(countMap);
}
●我们知道operator[]执行两个操作:
①是读(读取关键字),②是写(修改second的值)。
operator[]的参数是给定的关键字key,返回的是key对应的pair的second的类型的引用。 
●at操作:访问所给关键字的元素,带参数检查,如果所给关键字不在map中,则会抛出异常~ 
通过以上3种方法,我们求出了各种水果出现过的次数,
④▼接下来求出现次数最多的几种水果,我们可以采取以下的方法:

bool SortByM1( const pair<string,int> &v1, const pair<string,int> &v2)
{  
	return v1.second > v2.second;//降序排列  
} 

void SelectTop3(map<string , int>& m)
{
	map<string,int>::iterator ite = m.begin();
	vector<pair<string,int>>v;
	while(ite != m.end())
	{
		//v.push_back(pair<string,int>((*ite).first,(*ite).second));
		v.push_back(*ite);
		++ite;
	}
	std::sort(v.begin(),v.end(),SortByM1);
}

这种方法是在pair<string,int>类型的vector中放入的是pair类型元素,一定要注意sort的参数。
●我们不能直接对map进行调用sort~~ 
pair是一个结构体,push操作效率不高,我们可以在vector中放指向map的迭代器~代码如下:

void SelectTop3(map<string , int>& m)
{
	map<string,int>::iterator ite = m.begin();
	vector<map<string,int>::iterator> v;
	while(ite != m.end())
	{
		v.push_back(ite);
		++ite;
	}
	struct Compare
	{
		bool operator()(map<string,int>::iterator l,map<string,int>::iterator r)
		{
			return l->second > r->second;
		}
	};
	std::sort(v.begin(),v.end(),Compare());
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值