算法入门到进阶(二)——STL和基本数据结构(set和map)


set

set就是集合,STL的set是用二叉树实现,集合中的每一个元素只出现一次,并且是排好序的。访问元素的时间复杂度是O(log2n),非常的高效。

set和map一般在算法竞赛中应用是十分广泛的,特别是需要用二叉搜索树处理数据的题目,如果用set或map实现,能极大的简化代码。

set的相关操作

set< Type >A; //定义一个集合,Type表示数据类型,A表示集合变量的名称
A.insert(item); //把item放进set集合中
A.erase(item); //删除集合中的元素item
A.clear(); //清空集合
A.empty(); //判断集合是否为空
A.size(); //返回集合中元素个数
A.find(k);//返回一个迭代器,指向键值k
A.lower_bound(k);//返回一个迭代器,指向键值不小于k的第一个元素
A.upper_bound(k);//返回一个迭代器,指向键值大于k的第一个个元素

set案例:“产生冠军”

    有一群人打乒乓球比赛,两两捉对厮杀,每两个人之间最多打一场比赛。
球赛规则如下:
    如果A打败了B,B又打败了C,而A与C之间没有进行过比赛,那么就认定A一定能打败C.
    如果A打败了B,B又打败了C,而且C又打败了A,那么A,B,C三者都是不可能成为冠军。
    根据这个规则,无需循环较量,或许就能确定冠军。本题的任务就是对于一群比赛选手,在
经过了若干场厮杀之后,确定是否已经产生了冠军

源码

#include<iostream>
#include<string>
#include<set>  //引入set集合头文件
using namespace std;
int main() {
	set<string>A, B;  //定义集合A,B类型类string
	string s1, s2;    //s1表示赢了的人,s2表示有数过的人
	int n;
	cout << "n:";      //比赛场数
	while (cin >> n && n) {
		for (int i = 0; i < n; i++) {
			cout << "winner:s1 loser: s2 :";
			cin >> s1 >> s2;  //这里表示的是输入s1,s2对决,s1表示赢了的人,s2表示输了的人
			A.insert(s1);  //将赢了的人放进集合A
			A.insert(s2);  //将输过的人也装进集合A
			/*这里你可能会疑惑要是一个人赢了一场输了一场
			岂不是会存两次在A中,这个想法是对的,但是因为在STL中的
			set是用二叉树实现的,集合中的每一个元素只会出现一次,并且是
			排好序的,所以不会出现一个元素出现两次的情况,而我们的题目是
			针对人的,所以不会有两个一样的人*/
			
			B.insert(s2);//将有败绩的人放进集合B中
		}
		if ((A.size() - B.size()) == 1) {
			//如果所有的人减去失败的人结果为1就表示有冠军
			cout << "Yes" << endl;
		}
		else {//没有冠军
			cout << "None"<<endl;
		}
		A.clear();
		B.clear();//清空集合
	}
	return 0;
}

运行结果

在这里插入图片描述
在这里插入图片描述

分析

这个题的意思就是定义集合A和B,把所有人放进集合A,把所有有失败记录的放进集合B。
如果A-B=1.则可以判断出存在冠军,否则不能。

其实就是说,只要进行了对抗,有失败记录的就不能成为冠军。

在这里插入图片描述

map

这里有一个常见的问题:有n个学生,每人都有姓名name和学号id,现在给定一个学生的name,要求查找他的id。
简单的做法是定义string name[n]和int id[n](可以放在一个结构体中)存储信息,然后在name[ ]中查找这个学生,然后找到输出他的id。这样做的缺点是需要搜索所有的name[ ],复杂度是O(n),效率很低

利用STL中的map容器可以快速地实现这个查找,复杂度是O(log2n)。

map是一个关联容器,它实现从键(key)到值(value)的映射(是不是让你想起了哈希算法,但是不同哟)。map效率高的原因是它用平衡二叉树搜索树来存储访问。

在上面的例子中,map的具体操作如下。

  1. 定义:map< string,int >student,存储学生的name和id。
  2. 赋值:例如student[ “Tom”]=15。这里把”Tom“当作数组下标来使用(Tom就是键,15就是值)
  3. 查找:在找学号时,可以直接使用student[ “Tom”]来表示他的id,不用再去搜索所有的姓名。

map用起来很方便。对于它的插入,查找,访问等操作,可以自己在网上搜索资料。

案例:“Shopping”

女孩dandelion经常去购物,她特别喜欢一家叫"memory"的商店。由于春节快到了,所有商店
的价格每天都在上涨。她想知道这家商店每天的价格排序。
输入:
第一行是数字n(n<=10000),代表上商店的数量。
后面n行,每行有一个字符串(长度小于31,只包含小写字母和大写字母),表示商店的名称。
然后一行是数字m(1<=m<=50),表示天数。
后面又m部分,每部分有n行,每行是数字s和一个字符串p,表示商店p在这一天涨价s。
输出:
包含m行,第i行显示第i天后店铺"memory"的排名。排名的定义为如果有t个商店的价格
高于"memory",那么它的排名是t+1;

源码

#include<iostream>
#include<string>
#include<map>
using namespace std;

int main() {
	int n, m, p;
	map<string, int>shop;   //定义一个map容器shop
	cout << "n:";//表示商店数量
	while (cin >> n) {
		string s; //商店名字
		for (int i = 0; i < n; i++) {
			cout << i+1 << "商店名:";
			cin >> s;
		}
		cout << "m:";//表示天数
		cin >> m;
		while (m--) {
			cout << "第" << 3 - m << "天超市价格变化:" << endl;
			for (int i = 0; i < n; i++) {
				cout << "p:涨幅价格,s:商店名称:";
				cin >> p >> s;   //p表示这一天上涨的价格,s表示商店名
				shop[s] += p;    //map可以直接操作商店,加上价格
			}
			int rank = 1; //实现t+1的排名,就从1开始数
			map<string, int>::iterator it;  //获取map的迭代器
			for (it = shop.begin(); it != shop.end();it++) {
				if (it->second > shop["memory"]) { 
					//it->second表示第二个存储的值也就是商店的价格的涨幅
					rank++;
				}
			}
			cout << "memory排名:" << rank<< endl;
		}
		shop.clear();//清空map
	}
	system("pause");
	return 0;
}

运行结果

在这里插入图片描述

分析

在这里插入图片描述

注释已经写的很详细了,耐心看,一定能搞懂

总结

相信你已经理解并掌握了C++中STL的set和map的概念和操作。下一篇博客我们继续这个章节,分析sort函数和**next_permutation()**函数的概念和操做

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jacky~~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值