STL容器set和map的使用介绍

目录

  • 序列式容器和关联式容器
  • set使用介绍
  • multiset的介绍
  • map的使用介绍
  • multimap的说明

序列式容器和关联式容器

在STL中像vector list deque forward_list这样的容器,里面存储的数据元素是线性结构的,通过线性的数据结构来管理和操作,这样的容器就是序列式容器。
关联式容器的数据单位是一对键值对,即<key,value>结构的键值对,key和value有着对应关系,在数据检索时比序列式容器效率更高。
STL中的关联式容器有map、set、multimap、multiset,它们存储的数据类型就是键值对pair,是一种类模板。

template<class T1,class T2>
struct pair
{
   typedef T1 first_type;
   typedef T2 second_type;
  T1 first;
  T2 second;
  pair()
  :first(T())
  ,second(T())
  {}
  pair(const T1&a,const T2 &b)
  :first(a)
  ,second(b)
  {}
};

上述四种容器都是存储实例化的pair类型数据,set和multiset是只对key值操作的容器,可以认为它的pair类型是<key,key>。

set使用介绍

set底层使用的数据结构是红黑树,也是二叉搜索树的一种,所以我们往set中插入数据也是二叉搜索树的插入方式。

   set<int>s;
	s.insert(6);
	s.insert(9);
	s.insert(4);
	s.insert(2);
	s.insert(5);
	s.insert(8);
	s.insert(1);
	s.insert(1);
	s.insert(1);
	cout << s.size() << endl;
	auto it = s.begin();
	while (it != s.end())
	{
		cout << *it << " ";
		++it;
	}

在这里插入图片描述
set的插入就是往二叉搜索树插入数据,重复的数据不会插入,同时用迭代器依顺序取值打印就是树的中序遍历。

set的构造函数常用的就是默认构造,还有迭代器构造,用输入型迭代器即可。
在这里插入图片描述

vector<int>v = { 9,5,7,8,2 };
	  set<int>s(v.begin(),v.end());
	cout << s.size() << endl;
	auto it = s.begin();
	while (it != s.end())
	{
		cout << *it << " ";
		++it;
	}
}

在这里插入图片描述
迭代器类型用普通迭代器、反向迭代器、const修饰的迭代器
在这里插入图片描述
同样有存储数据数量成员函数size,是否为空成员函数empty,其他一些查找find 删除erase 清空clear基本同其他容器用法相同。

multiset的介绍

multiset和set的区别就是能够存储相同的数据。

multiset<int>s;
	s.insert(6);
	s.insert(9);
	s.insert(4);
	s.insert(2);
	s.insert(2);
	s.insert(5);
	s.insert(8);
	s.insert(1);
	s.insert(1);
	s.insert(1);
	for (auto e : s)
		cout << e << " ";
	cout << endl;
	auto it = s.find(2);
	while (it != s.end() && *it == 2)
	{
		auto next = it;
		++next;
		s.erase(it);
		it = next;
	}
	for (auto e : s)
		cout << e << " ";

上面对multiset简单的使用了一下,可以看成multiset可以存储相同的数据,find()查找数据时没找到就返回末尾迭代器,找到了如果有多个就返回中序遍历的最前面一个数的迭代器
在这里插入图片描述
set和multiset的erase()删除指定数据会返回成功删除了的数据个数。

map的使用介绍

map是存储具体的pair数据类型的,测试map的插入数据

map<string, string>dict;
	dict.insert(pair<string, string>("sort", "排序"));
	pair<string, string>kv("algorithm", "算法");
	dict.insert(kv);
	dict.insert(make_pair("test", "测试"));
	map<string, string>::iterator it = dict.begin();
	while (it != dict.end())
	{
		cout << (*it).first << " " << it->second << endl;
		++it;
	}

这里来插入英文和中文对应的两个字符串这种类型是pair<string,string>,代码也演示了插入pair的三种方式

  • 用临时变量的方式有参构造pair类型来插入。
  • 创建一个pair变量再插入。
  • 用pair类模板中的成员函数make_pair,此函数就是返回一个pair变量,刚好插入到map中。

用迭代器方式遍历也是中序遍历,是按照pair的第一个值first也是就key来构建树的。
在这里插入图片描述
就是按字符串比较大小的方式排序。

可以用map来做存储语言互译程序的底层结构。平时还可以用map来计数,比如统计水果受喜爱的投票计数

map<string, int>countmap;
	string arr[] = { "苹果","苹果","香蕉","西瓜","苹果","香蕉","香蕉", "香蕉","樱桃" };
for (auto& e : arr)
{
		auto kv = countmap.find(e);
		if (kv != countmap.end())
			++kv->second;
		else
			countmap.insert(make_pair(e, 1));
	}

上面代码就是统计水果的一种方案,起初是没找到,然后插入,计数为1,后面找到了这种水果就计数++。这种方案弊端是在没有找到时,会插入,这种情况就查找了两次,find一次insert一次,find和insert都会对树从根开始往下查找。

方案二

for (auto& e : arr)
{
auto kv = countmap.insert(make_pair(e, 1));
if (kv.second == false)
    kv.first->second++;
}

这里就利用了map的插入函数的特性
在这里插入图片描述 insert的返回值是pair<iterator,bool>,插入时,如果树中已经有相同key值的pair,返回值的second值就是false,否则是true,第一个值是个迭代器,是要插入的pair的迭代器,插入成功指向新插入的pair,失败就说明原先就有了相同key的pair,就指向原先的pair,不管插入成功与否都指向我们指定的key的pair,上面代码每次都是插入一种水果计数为1,如果返回的pair的second=false说明原先就有,计数++达到计数的效果。
这里不管成功与否都会指向要统计的水果,不管那种情况只查找了一次,比方案一更优。

map还重载了[]
在这里插入图片描述
以key值为索引返回value值的引用
实现这样功能的方法就是以下对insert的使用
在这里插入图片描述
可以把说明复杂的代码分解一下

auto pair=insert(make_pair(k,mapped_type()));
auto kv=*(pair.first);
kv.second;

我们要操作指定key对应的value值 直接利用上面就讲过的insert的特性,插入一个pair,第一个值first是我们指定的key,second直接用类型的默认构造就好了,返回的pair第一个值是迭代器指向我们指定key的pair,我们不用到返回pair的second,就对指向的pair解引用拿到我们要找的有指定key的pair,来操作里面的second,从而达到了用key索引返回value的目的。

利用[]我们可以设计出统计水果的方案三

for (auto& e : arr)
countmap[e]++;

pair的second是int类型,默认构造就是初始化为0,插入一种水果,对它的计数++,代码简洁效率又高。

multimap的说明

multimap就是可以存重复key值的特殊map,还有一点区别就是multimap中没有重载[],因为可能有多个相同key值的pair,这时就不知道要返回那个的value了。

上面对水果计数三种方案的效果都如下图
在这里插入图片描述
既然已经计数了,再想想如果根据计数来排序,显示员工最喜欢的前k中水果。

int main()
{
vector<string>v = { "苹果","香蕉","草莓","香蕉","苹果","苹果","西瓜","橘子","西瓜","西瓜","西瓜" };
	GetFavoriteFruit(v, 3);
    return 0}

用一个GetFavoriteFruit函数来计数和显示排名前k的水果。

void GetFavoriteFruit(const vector<string>& fruits, size_t k)  //显示员工最喜欢吃的前k中水果
{
	map<string, int>m;  //这里就用到了前面计数的方案三
	for (auto& e : fruits)
		m[e]++;
vector<pair<string, int>>v(m.begin(), m.end());         
	sort(v.begin(), v.end(), congreat());
	for (int i = 0; i < k; ++i)
	cout << v[i].first << "  " << v[i].second << endl;

用排序方式, 方式1 先用map统计各种水果的投票,在把map中的元素拷贝到vector中进行排序,用仿函数控制排序方式,algorithm中的sort必须传入随机迭代器,而map中的迭代器是双向迭代器,所以可以把map中一个个的pair数据赋值到vector中。

struct congreat
{
	bool operator()(const pair<string, int>& L, const pair<string, int>& R)
	{
		return L.second > R.second;
	}
};

把map中的数据pair一个个挪到vector中起始开销挺大的,vector中也可以存map的迭代器,用仿函数控制给迭代器排序,然后遍历迭代器也可以达到排序效果

struct itgreat
{
	bool operator()(const map<string, int>::iterator& L, const map<string, int>::iterator& R)
	{
		return L->second > R->second;
	}
};
vector<map<string, int>::iterator>v;        
	auto it = m.begin();
	while (it != m.end())
	{
		v.push_back(it);
		++it;
	}
	sort(v.begin(), v.end(), itgreat());
	for (int i = 0; i < k; ++i)
	{
		cout << v[i]->first << "  " << v[i]->second << endl;
	}

也可以使用堆的方式对map中的pair或者迭代器排序,达到效果。

struct conless
{
	bool operator()(const pair<string, int>& L, const pair<string, int>& R)
	{
		return L.second < R.second;
	}
};
priority_queue<pair<string, int>, vector<pair<string, int>>, conless>q; 
// 用堆来排序,1   同样堆可以存map的元素,或者map的迭代器,用仿函数分别控制排序方式
	for (auto& e : m)
   {
		q.push(e);
	}
	while (k--)
	{
		auto& top = q.top();
		cout << top.first << " " << top.second << endl;
		q.pop();
	}
struct itless
{
	bool operator()(const map<string, int>::iterator& L, const map<string, int>::iterator& R)
	{
		return L->second < R->second;
	}
};
priority_queue<map<string, int>::iterator, vector<map<string, int>::iterator>, itless>q;  //2  堆中存map迭代器
	auto it = m.begin();
	while (it != m.end())
	{
		q.push(it);
		++it;
	}
	while (k--)
	{
		auto& top = q.top();
		cout << top->first << " " << top->second << endl;
			q.pop();
	}

最后还可以用multimap来操作,先用map统计好数据后,让后让map中的pair的first去作为要插入到multimap中的pair的second,second就作为first。


multimap<int, string, greater<int>>sortm;         
   //把统计好数据的map m的数据又放到multimap中用投票数作key,改变仿函数,中序遍历打印出降序来,达到同样的效果,用multimap处理有票数相等的情况
	for (auto& e : m)
	{
		sortm.insert(make_pair(e.second, e.first));
	}
	auto it = sortm.begin();
	while (k--)
	{
		cout << it->second << "  " << it->first << endl;
		++it;
	}

最终效果都是
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值