STL初步--例题

5.2.1 排序与检索

例题5-1 大理石在哪:
【题目描述】
现有N个大理石,每个大理石上写了一个非负整数、首先把各数从小到大排序;然后回答Q个问题。每个问题问是否有一个大理石写着某个整数x,如果是,还要回答哪个大理石上写着x。排序后的大理石从左到右编号为1~N。
(在样例中,为了节约篇幅,所有大理石的数合并到一行,所有问题也合并到一行。)

【样例输入】
4 1
2 3 5 1
5
5 2
1 3 3 3 1
2 3

【样例输出】
CASE# 1:
5 found at 4
CASE# 2:
2 not found
3 found at 3

分析:
非常简单的一道题,可以用STL实现让代码更简洁。
涉及到两个函数记录如下:
(1)sort(a,a+n) 对于给定区间内的所有数进行排序
(2)lower_bound(a,a+n,x) 查找大于或等于x的第一个位置
代码:

#include<iostream>
#include<Windows.h>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#define MAXN 1000
#define INF 0x3f3f3f3f
using namespace std;
int main()
{
	int n, q, t, x;
	int a[MAXN], cnt = 1;
	while (scanf("%d%d", &n, &q) == 2 && n)
	{
		for (int i = 0;i < n;i++)
			cin >> a[i];
		cout << "CASE# " << cnt++ << ':' << endl;
		sort(a, a + n);
		for (int i = 0;i < q;i++)
		{
			cin >> x;
			t = lower_bound(a, a + n, x) - a;	//查找大于等于x的第一个位置
			if (a[t] == x) 
				cout << x << " found at " << t + 1<< endl;
			else
				cout << x << " not found\n";
		}
	}
	system("pause");
	return 0;
}

5.2.2 不定长数组:vector

vector就是一个不定长数组。不仅如此,它把一些常用操作“封装”在了vector类型内部。例如,若a是一个vector,可以用
a.size()读取它的大小,a.realize()改变大小,a.push_back()向尾部添加元素,a.pop_back()删除最后一个元素。

5.2.3 集合:set

集合set的性质:1.相同元素最多只出现一次 2.集合中元素默认按升序排列
声明:set< string >SET
涉及到的操作:SET.insert(something)

例题5-3 安迪的第一个字典:
【问题描述】输入一个文本,找出所有不同的单词(连续的字母序列),按字典序从小到大输出。单词不区分大小写。

【样例输入】

Adventures in Disneyland

Two blondes were going to Disneyland when they came to a fork in the
road. The sign read: “Disneyland Left.”

So they went home.

【样例输出】
a
adventures
blondes
came
disneyland
(为节约篇幅仅保留前5行)

分析:
对于每个输入的string,由于不区分大小写且考虑到中间可能含有非字母的元素,故先对字符串进行处理:
(1)若为字母,统一成小写 (2)若非字母,将该字符变为空格(即使字符串划分为多个单词)

代码:

#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#define MAXN 1000
using namespace std;
set<string> dict;	//string集合
int main()
{
	string str, buf;
	while (cin >> str)
	{
		if (str[0] == '1') break;
		for (int i = 0;i < str.length();i++)	//处理字符统一为小写
			if (isalpha(str[i])) str[i]=tolower(str[i]);else str[i] = ' ';
		stringstream ss(str);	//将读入的str分开
		while (ss >> buf) dict.insert(buf);
	}
	for (set<string>::iterator it = dict.begin();it != dict.end();it++)
		cout << *it << '\n';
	system("pause");
	return 0;
}

5.2.4 映射:map

map就是从“键”到“值”的映射。 例如可以用一个map<string,int>month_name来表示“月份名字到月份编号”的映射,然后可以通过math_name[“July”]=7这样来赋值。
例题5-4 反片语
【题目描述】
输入一些单词(以“#”为结束标志),找出所有满足如下条件的单词:该单词不能通过字母的重排,得到输入文本中的另一个单词。在判断是否满足条件是不分大小写,但是在输出时应保留输入时的大小写,按字典序进行排列(所有大写字母在所有小写字母前面)。

【样例输入】
ladder came tape soon leader acme RIDE lone Dreis peat
ScAlE orb eye Rides dealer NotE derail LaCeS drIed
noel dire Disk mace Rob dries

【样例输出】
Disk
NotE
derail
drIed
eye
ladder
soon

解析:
采用将输入标准化 的思想。何为标准化?因为在判断是否满足条件时,字母不分大小写,且鉴于“该单词不能通过字母重排,得到输入文本中另一个单词”的特点,可以采用单词映射来完成,因此就要对单词进行小写转化+排序。
具体做法是:
先将单词中所有字母进行小写转化,再对转化后的字母进行排序,这样,由固定几个字母组成的有序序列便构成了唯一的映射。
对于每个输入的单词,将它映射到map中,并使计数器+1 。在最后判断时,只要计数器有一个元素,就证明存在这样的唯一的单词。
还有一点需要注意的是:比较时不区分字母大小写和排列顺序,但是最终输出的时候需要原样输出,这就可以用前面学到的不定长数组vector来解决,声明为:vector< string > words;

代码:

#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<vector>
#include<set>
#include<map>
#define MAXN 1000
using namespace std;
vector<string> words;
map<string, int> ans;
string resp(string t)	//标准化,排序+转化为小写
{
	string str = t;
	for (int i = 0;i < str.length();i++)
		str[i] = tolower(str[i]);
	sort(str.begin(), str.end());
	return str;
}
int main()
{
	string str;
	while (cin >> str)
	{
		if (str[0] == '#') break;
		words.push_back(str);
		string t = resp(str);
		if (!ans.count(t)) ans[t] = 0;	//count返回是否含有被查找元素,0/1
		ans[t]++;
	}
	vector<string>dict;
	for (int i = 0;i < words.size();i++)
		if (ans[resp(words[i])] == 1) dict.push_back(words[i]);
	sort(dict.begin(), dict.end());
	for (int i = 0;i < dict.size();i++)
		cout << dict[i] << endl;
	system("pause");
	return 0;
}

5.2.5 栈、队列与优先队列

1.栈:先进后出 2.队列:先进先出
头文件:#include< stack > 定义:stack< int >s
相关操作:s.push() s.pop() s.top()

例题 5-5 集合栈计算器
【题目描述】详见书上
分析:
为每个不同的集合分配一个唯一的ID,则每个集合都可以表示成所包含元素的ID集合,这样就可以用STL的set来表示了,而整个栈则是一个stack。
代码:

#include<iostream>
#include<stack>
#include<set>
#include<map>
#include<vector>
#include<string>
#include<iterator>
#include <algorithm>
using namespace std;

#define ALL(x) x.begin(), x.end()//所有的内容
#define INS(x) inserter(x, x.begin())//插入迭代器
typedef set<int> Set;
map<Set, int> IDcache; //把集合映射成ID
vector<Set> Setcache; //根据ID取集合

					 
int ID(Set x) {	 //查找给定集合x的ID。如果找不到,分配一个新ID
	if (IDcache.count(x)) return IDcache[x];
	Setcache.push_back(x);//添加集合
	return IDcache[x] = Setcache.size() - 1;
}

int main() {
	int T;
	cin >> T;
	while (T--) {
		stack<int> s;//题目中的栈
		int n;
		cin >> n;
		for (int i = 0; i < n; i++) {
			string op;
			cin >> op;
			if (op[0] == 'P') s.push(ID(Set()));
			else if (op[0] == 'D') s.push(s.top());
			else {
				Set x1 = Setcache[s.top()]; s.pop();	
				Set x2 = Setcache[s.top()]; s.pop();
				Set x;
				if (op[0] == 'U') set_union(ALL(x1), ALL(x2), INS(x)); 	//取并集并放入x
				if (op[0] == 'I') set_intersection(ALL(x1), ALL(x2), INS(x));		//取交集并放入x
				if (op[0] == 'A') { x = x2; x.insert(ID(x1)); }
				//cout << "................." << x.size() << endl;//测试语句
				s.push(ID(x));
			}
			cout << Setcache[s.top()].size() << endl;
		}
		cout << "***" << endl;
	}
	system("pause");
	return 0;
}

例题5-6 团体队列
【题目描述】
见算法书
代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<queue>
#include<map>
const int maxn = 1000 + 10;
using namespace std;
int main()
{
	int t, kase = 0;
	while (scanf("%d", &t) == 1 && t)
	{
		printf("Scenario #%d\n", ++kase);
		//记录所有人的团队编号
		map<int, int> team;		//team表示人员编号到队伍编号的映射
		for (int i = 0;i < t;i++)
		{
			int n, x;
			scanf("%d", &n);
			while (n--) { scanf("%d", &x);team[x] = i; }
		}

		//模拟
		queue<int> q, q2[maxn];
		for (;;)
		{
			char cmd[10];
			int x;
			scanf("%s", cmd);
			if (cmd[0] == 'S') break;
			else if (cmd[0] == 'D') {
				int t = q.front();
				printf("%d\n", q2[t].front());q2[t].pop();
				if (q2[t].empty()) q.pop();
			}
			else if (cmd[0] == 'E') {
				scanf("%d", &x);
				int t = team[x];
				if (q2[t].empty()) q.push(t);	//团队t进入队列
				q2[t].push(x);
			}
		}
		printf("\n");
	}
	system("pause");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值