5.2 STL初步
这一章节我们主要介绍C++的标准模板库。
5.2.1 排序与检索
关于sort的内容,我在4.2 函数调用与参数传递已经介绍的非常详细了。
事实上由于sort是一个模板函数,sort是可以对任意对象(不一定是内置类型)进行排序的。
5.2.2 不定长数组 vector
vector是一个封装了动态大小(不固定)数组的顺序容器,它能够存放任意类型的对象。不仅如此,它还将一些常用的操作封装在了vector类型的内部。
首先我们看一下怎么声明一个vector:
//vector<变量类型名>变量名
#include<cstdio>
#include<iostream>
#include<vector>
using namespace std;
int main(){
vector<int> a;//这类似于int a[]
return 0;
}
需要注意到vector是一个模板类,所以需要这样的方式去声明。vector中封装的函数见此(具体的内容我们接下来一边做题一边分析):vector 容器浅析
木块问题 (UVA 101)
从左到右n个木块,编号为0~n-1,要求模拟以下四种操作:
move a onto b:将a和b上方的木块全部归位,然后把a放在b上
move a over b:把a上方的木块全部归位,然后将a放在b所在的木块堆的顶部
pile a onto b:把b上方的木块全部归位,然后把a及上面的木块整体放在b上
pile a over b:把a及a上方的木块全部放在b所有木块堆的顶部
输入一堆指令,如果a和b为同一堆的即为非法指令,即忽略。所有操作结束后输出每个位置的木块列表,按照从底部到顶部的顺序排列。
分析:显然又是一道模拟题,这里我们用vector去保存每个木块堆的高度进行处理:
#include<cstdio>
#include<iostream>
#include<vector>
using namespace std;
const int maxn=30;
int n,a,b;
vector<int>pile[maxn];//表示多个木块堆
int main(){
cin>>n;
for (int i=0;i<n;i++) pile[i].push_back(i);
return 0;
}
这里push_back表示在这个vector的尾部加入一个数据。这里的意思是在每一个pile后面添加一个i的值。(pop_back()即为删除尾部元素的意思)
接下来我们看这个问题,首先我们需要一个函数得到当前指令的木块现在在这个木块堆的哪一个堆里:
void find_block(int a,int &p,int &q){
//如果不明白这里为什么用引用的再好好看一看上一章
for (p=0;p<n;p++){
for (q=0;q<pile[p].size();q++) if (pile[p][q]==a) return;
}
}
这里用了一个.size(),即表示一个vector的大小。
查找得到了指令中木块的当前位置,p为所在堆,q为所在高度。如果两个木块的所在堆相同,即直接跳过这个指令。接下来观察这四个指令,我们可以发现,这四个指令其实是由以下两个简单命令合成的:
1.将x木块上方的木块全部归位
2.把x木块上的所有木块整体移动到另一个堆
接下来我们编译这两个简单命令的函数:
void clear_above(int p,int h){
for (int i=h+1;i<pile[p].size();i++){
int b=pile[p][i];
pile[b].push_back(b);//放回原堆
}
pile[p].resize(h+1); //pile只保留下标0~h的元素
}
需要注意的是,这里resize不是保留元素的意思,resize(int n,element)表示改变vector的的大小。如果说n小于当前的大小,即截取下标为n以后所有的元素(包括自身),如果n大于当前的大小,即进行扩容,扩充后的多出来的每个元素值为element。
同理:
// 把第p堆高度为h的木块上方的所有木块(包括高度为h的木块自身)移动到p2的顶部
void pile_onto(int p,int h,int p2){
for (int i=h;i<pile[p].size();i++)
pile[p2].push_back(pile[p][i]);//移位
pile[p].resize(h);
}
于是指令的部分即为:
while (cin>>s1>>a>>s2>>b){
//输入指令
int pa,ha,pb,hb;//两个木块当前所在的堆和高度
find_block(a,pa,ha);
find_block(b,pb,hb);
if (pa==ba) continue;
if (s2=="onto") clear_above(pb,hb)
if (s1=="move") clear_above(pa,ha)
pile_onto(pa,ha,pb);
}
其实这道题最重要的是要知道,当我们a上面的木块全部归位,然后把a放在别的木块上时,即为把a及a上面的木块放在别的木块上
5.2.3 集合 set
set声明的方式和vector是一样的:
#include<cstdio>
#include<iostream>
#include<set>
using namespace std;
int main(){
set<int> a;//这类似于int a[]
return 0;
}
这里我们还是看例题进行说明:
安迪的第一个字典 (UVA 10815)
输入一个文本,找出所有不同的单词(连续的字母序列,按字典序从小到大输出,单词全部转为小写)
分析:set作为容器正好契合这道题的属性,因为set中的每个元素最多出现过一次且无法更改,set还将这些元素自动进行了排序。于是我们只需要将这些字符串中的每一个单词全部转为小写然后添加到set中即可得到结果。
代码如下:
#include<cstdio>
#include<iostream>
#include<set>
#include<string>
using namespace std;
set<string>dict