STL是指C++的标准模版库(Standard Template Library)。本节介绍STL中的一些常用算法和容器。
排序与检索
sort使用 数组元素默认的大小比较运算符进行排序,只有在需要按照特殊依据进行排序时才需要传入 额外的比较函数。
sort可以对任意对象进行排序,不一定是内置类型。如果希望用sort排序,这个类 型需要定义“小于”运算符,或者在排序时传入一个“小于”函数。
现有N个大理石,每个大理石上写了一个非负整数。首先把各数从小到大排序,然后回 答Q个问题。每个问题问是否有一个大理石写着某个整数x,如果是,还要回答哪个大理石上 写着x。排序后的大理石从左到右编号为1~N。(在样例中,为了节约篇幅,所有大理石上 的数合并到一行,所有问题也合并到一行。)
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 10000;
int main() {
int n, q, x, a[maxn], kase = 0;
while (scanf("%d%d", &n, &q) == 2 && n) //判断scanf的返回值
{
printf("CASE# %d:\n", ++kase);
for(int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
sort(a, a+n);
while (q--)
{
scanf("%d", &x);
int p = lower_bound(a, a+n, x) - a; //在已排序数组a中寻找x
if (a[p] == x)
{
printf("%d found at %d\n", x, p+1);
}
else
{
printf("%d not found\n", x);
}
}
}
}
2 3 5 1
CASE# 1:
5
5 found at 2
关于scanf
:
- 输入两个整形,scanf的返回值就等于2;如果输入了一个整形另一个其它类型scanf的返回值就是1;如果两个都不是输入正新就返回0.
- scanf的返回值就是输入类型正确的个数
vector——不定长数组
vector就是一个不定长数组。不仅如此,它把一些常用操作“封装”在了vector类型内部。
eg. a是一个vector
a.size( )
读取它的大小a.resize( )
改变大小a.push_back( )
向尾部添加元素a.pop_back( )
删除最后一个元素
vector是一个模板类:
- 声明变量:
vector<int>a
或者vector<double>b
Vector<int>
是一个类似于inta[]的整数数组,而vector<string>
就是一个类似于 stringa[ ]的字符串数组- 它们可以直接赋值,还可以作为 函数的参数或者返回值,而无须像传递数组那样另外用一个变量指定元素个数
set——集合
集合与映射也是两个常用的容器。set就是数学上的集合——每个元素最多只出现一次。 和sort一样,自定义类型也可以构造set,但同样必须定义“小于”运算符。
安迪的第一个字典(Andy’s First Dictionary,Uva 10815)
输入一个文本,找出所有不同的单词(连续的字母序列),按字典序从小到大输出。单 词不区分大小写。
样例输入: 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.
样例输出(为了节约篇幅只保留前5行):
a
adventures
blondes
came
disneyland
#include<iostream>
#include<string>
#include<set>
#include<sstream>
using namespace std;
set<string> dict; //string 集合
int main() {
string s, buf;
while (cin >> s)
{
for (int i = 0; i < s.length(); i++)
{
if(isalpha(s[i])) {
s[i] = tolower(s[i]);
}
else
{
s[i] = ' ';
}
stringstream ss(s);
while (ss >> buf)
{
dict.insert(buf);
}
}
for(set<string>::iterator it = dict.begin(); it != dict.end; ++it) {
cout << *it << "\n";
}
}
return 0;
}
上面的代码用到了set中元素已从小到大排好序这一性质,用一个for循环即可从小到大 遍历所有元素
iterator的意思 是迭代器,是STL中的重要概念,类似于指针。
map——映射
map就是从键(key)到值(value)的映射。因为重载了[ ]运算符,map像是数组的“高 级版”。
可以用一个map<string,int>month_name来表示“月份名字到月份编号”的映射, 然后用month_name[“July”]=7这样的方式来赋值。
栈、队列与优先队列
STL还提供3种特殊的数据结构:栈、队列与优先队列。
栈
栈,就是符合“后进先 出”(Last In First Out,LIFO)规则的数据结构,有PUSH和POP两种操作,其中PUSH把元素 压入“栈顶”,而POP从栈顶把元素“弹出”。
STL的栈定义在头文件<stack>
中,可以用“stack<int>s
”方式声明一个栈。
队列
队列是符合“先进先出”(First In First Out,FIFO)原则的“公平队列”
STL队列定义在头文件<queue>
中,可以用“queue<int>s
”方式声明一个队列
优先队列
优先队列是一种抽象数据类型(Abstract Data Type,ADT),行为有些像队列,但先出 队列的元素不是先进队列的元素,而是队列中优先级最高的元素。
STL的优先队列也定义在头文件<queue>
里,用“priority_queue<int>pq
”来声明。这个pq是 一个“越小的整数优先级越低的优先队列”。由于出队元素并不是最先进队的元素,出队的方 法由queue的front( )变为了top( )。
对于一些常见的优先队列,STL提供了更为简单的定义方法,例如,“越小的整数优先级 越大的优先队列”可以写成“priority_queue<int,vector,greater>pq”。注意,最后两 个“>”符号不要写在一起,否则会被很多(但不是所有)编译器误认为是“>>”运算符