最近几天学了STL的一些容器,大概用了一下,不得不承认,有些真的还挺好用的!
先学了vector,vector是一种序列式容器,和数组很像,但是比数组好的就是空间上可以动态调整,并且可以在中间进行插入和删除。
如果要使用vector就要在一开始加上:
#include
using namespace std;
vector<T>a
这里面T是容器里面元素的类型,a是容器的名字。
然后以上面这个容器讲讲vector的几个操作:
a.size():容器a的大小;
a.resize(h):让容器a只保留0~h-1个数,这个操作也可以用来进行末尾数的删除操作;
a.push_back(b):把b元素放到a容器的末尾;
a.clear:清空a中的元素;
a.pop_back:删除a的最后一个元素;
a.insert(n,m,k):在a的开头第n个元素(从0个开始算)的位置插入m个k;
a.erase(n,m):从a的第n个元素删除到a的第m个元素;
这是我发现的关于vector比较好的一篇博客
下面是例题
The Blocks Problem
Many areas of Computer Science use simple, abstract domains for both analytical and empirical studies. For example, an early AI study of planning and robotics (STRIPS) used a block world in which a robot arm performed tasks involving the manipulation of blocks.
In this problem you will model a simple block world under certain rules and constraints. Rather than determine how to achieve a specified state, you will “program” a robotic arm to respond to a limited set of commands.
The problem is to parse a series of commands that instruct a robot arm in how to manipulate blocks that lie on a flat table. Initially there are n blocks on the table (numbered from 0 to n-1) with block bi adjacent to block bi+1 for all 0 <= i < n-1 as shown in the diagram below:
The valid commands for the robot arm that manipulates blocks are:
move a onto b
where a and b are block numbers, puts block a onto block b after returning any blocks that are stacked on top of blocks a and b to their initial positions.
move a over b
where a and b are block numbers, puts block a onto the top of the stack containing block b, after returning any blocks that are stacked on top of block a to their initial positions.
pile a onto b
where a and b are block numbers, moves the pile of blocks consisting of block a, and any blocks that are stacked above block a, onto block b. All blocks on top of block b are moved to their initial positions prior to the pile taking place. The blocks stacked above block a retain their order when moved.
pile a over b
where a and b are block numbers, puts the pile of blocks consisting of block a, and any blocks that are stacked above block a, onto the top of the stack containing block b. The blocks stacked above block a retain their original order when moved.
quit
terminates manipulations in the block world.
Any command in which a = b or in which a and b are in the same stack of blocks is an illegal command. All illegal commands should be ignored and should have no affect on the configuration of blocks.
Input
The input begins with an integer n on a line by itself representing the number of blocks in the block world. You may assume that 0 < n < 25.
The number of blocks is followed by a sequence of block commands, one command per line. Your program should process all commands until the quit command is encountered.
You may assume that all commands will be of the form specified above. There will be no syntactically incorrect commands.
Output
The output should consist of the final state of the blocks world. Each original block position numbered i ( 0 <= i < n where n is the number of blocks) should appear followed immediately by a colon. If there is at least a block on it, the colon must be followed by one space, followed by a list of blocks that appear stacked in that position with each block number separated from other block numbers by a space. Don’t put any trailing spaces on a line.
There should be one line of output for each block position (i.e., n lines of output where n is the integer on the first line of input).
Sample Input
10
move 9 onto 1
move 8 over 1
move 7 over 1
move 6 over 1
pile 8 over 6
pile 8 over 5
move 2 over 1
move 4 over 9
quit
Sample Output
0: 0
1: 1 9 2 4
2:
3: 3
4:
5: 5 8 7 6
6:
7:
8:
9:
#include
#include
#include
#include
#include
#include
using namespace std;
vector<int>v[24];
int n;
void find_pile_hight(int a,int &p,int &h){ //求出木块a所在的堆数和高度
for(p=0;p<n;p++){
for(h=0;h<v[p].size();h++){ //v.size()是一个堆的大小
if(v[p][h]==a) return;
}
}
}
void clear_above(int p,int h){ //把第p堆高h以上的木块放回原来的位置
for(int i=h+1;i<v[p].size();i++){
int b=v[p][i]; //b为p堆上高h位置的数
v[b].push_back(b); //把b放回b原来所在的b堆
}
v[p].resize(h+1); //让p堆只保留0~h个数,相当于把h以上的数全部从p堆删掉
}
void moveonto(int a,int b){ //把a、b上的木块放回各自原来的位置,再把a放到b上
int pa,ha,pb,hb;
find_pile_hight(a,pa,ha); //找出a所在的堆数和高度
find_pile_hight(b,pb,hb);
if(pa!=pb){
clear_above(pa,ha); //把a上面的木块放回原来的位置
clear_above(pb,hb);
v[pb].push_back(a); //把a放到b所在的堆上
v[pa].resize(ha); //让a原来在的那个堆的只保留0~(ha-1),相当于把a从这个堆删掉
}
}
void moveover(int a,int b){ //把a上的木块放回各自的原来的位置,再把a放到包含了b的堆上
int pa,ha,pb,hb;
find_pile_hight(a,pa,ha);
find_pile_hight(b,pb,hb);
if(pa!=pb){
clear_above(pa,ha);
v[pb].push_back(a);
v[pa].resize(ha);
}
}
void pileonto(int a,int b){ //把b上的木块放回各自的原来的位置,再把a以及在a上面的木块放到b上
int pa,ha,pb,hb;
find_pile_hight(a,pa,ha);
find_pile_hight(b,pb,hb);
if(pa!=pb){
clear_above(pb,hb);
for(int i=ha;i<v[pa].size();i++){ //把a以及在a上面的木块放到b上
v[pb].push_back(v[pa][i]);
}
v[pa].resize(ha);
}
}
void pileover(int a,int b){ //把a连同a上木块放到包含了b的堆上
int pa,ha,pb,hb;
find_pile_hight(a,pa,ha);
find_pile_hight(b,pb,hb);
if(pa!=pb){
for(int i=ha;i<v[pa].size();i++){
v[pb].push_back(v[pa][i]);
}
v[pa].resize(ha);
}
}
int main(int argc,char const*argv[]){
scanf("%d",&n);
for(int i=0;i<n;i++){
v[i].push_back(i);
}
string str1,str2;
cin>>str1;
while(str1!="quit"){
int a,b;
cin>>a>>str2>>b;
if(str1=="move"&&str2=="onto") moveonto(a,b);
if(str1=="move"&&str2=="over") moveover(a,b);
if(str1=="pile"&&str2=="onto") pileonto(a,b);
if(str1=="pile"&&str2=="over") pileover(a,b);
cin>>str1;
}
for(int i=0;i<n;i++){
printf("%d:",i);
for(int j=0;j<v[i].size();j++){
printf(" %d",v[i][j]);
}
printf("\n");
}
return 0;
}
然后是deque容器,和vector差不多,不同的地方就是可以在头部插入和删除元素。
具体操作和vector也差不多,开头要使用
#include
using namespace std;
deque<T>a;
具体操作和vector也非常像,
就是多了一个a.push_front(b):把b放到a的首部;
然后这个是关于deque的一个比较不错的博客
下面是例题
Broken Keyboard
You’re typing a long text with a broken keyboard. Well it’s not so badly broken. The only problem
with the keyboard is that sometimes the “home” key or the “end” key gets automatically pressed
(internally).
You’re not aware of this issue, since you’re focusing on the text and did not even turn on the
monitor! After you finished typing, you can see a text on the screen (if you turn on the monitor).
In Chinese, we can call it Beiju. Your task is to find the Beiju text.
Input
There are several test cases. Each test case is a single line containing at least one and at most 100,000
letters, underscores and two special characters ‘[’ and ‘]’. ‘[’ means the “Home” key is pressed
internally, and ‘]’ means the “End” key is pressed internally. The input is terminated by end-of-file
(EOF).
Output
For each case, print the Beiju text on the screen.
Sample Input
This_is_a_[Beiju]_text
[[]][][]Happy_Birthday_to_Tsinghua_University
Sample Output
BeijuThis_is_a__text
Happy_Birthday_to_Tsinghua_University
#include
#include
#include
#include
#include
#include
using namespace std;
deque<string>dq; //创建一个空的deque容器dq
string s,temp;
int main(int argc,char const*argv[]){
while(cin>>s){
char op=0;
temp.clear(); //字符串temp清空
for(int i=0;i<s.size();i++){
if(s[i]=='['||s[i]==']'){ //如果扫到home键或者end键
if(op=='[') //第一次扫到home键的时候op还为0,进入不了if条件
dq.push_front(temp);
else //但是能进这个条件,不管扫到什么键,这个键之前的字符串都要放入dq中
dq.push_back(temp);
op=s[i]; //给op赋上字符,这个字符之后的字符串在遇上另一个特殊字符的时候就可以被放到dq的前面或者后面了
temp.clear(); //字符串temp清空
}
else
temp+=s[i];
if(i==s.size()-1){ //处理最后一段字符串
if(op=='[') //如果前一次给op赋上的字符是'[',就把最后一段temp放到dq容器首
dq.push_front(temp);
else //否则就直接放最后面
dq.push_back(temp);
temp.clear();
}
}
while(!dq.empty()){ //从deque容器中逐个输出字符,直到容器空了
printf("%s",dq.front().c_str()); //dq.front():容器第一个元素的引用,c_str():将内容以C_string的返回
dq.pop_front(); //删去容器的第一个元素
}
printf("\n");
}
return 0;
}
然后是map,map真的很好用,它是STL的一个关联容器, 一个map是一个键值(key, value)对的序列,key和value可以是任意的类型。在一个map中key值是唯一的。map提供一对一的数据处理能力,在编程需要处理一对一数据的时候,可以采用map进行处理。
简单来说map就相当于一个二维数组,但是这个数组不仅能存数字,还能存各种类型的元素,而且数组的下标只能是数字,但是map的下标(也就是key)也可以是任何类型。
以下是使用map需要的代码
#include
using namespace std;
map<string,string>mp;
这是定义了一个key为string类型,并且元素也为string类型的map容器,容器名叫mp;
具体的使用其实和数组差不多,但是要注意就是比如我这里定义的key是一个string类型,那么string有的性质key都有,比如用for循环给key赋值:
for(int i=0;i<n;i++){
scanf("%c",k[i]);
getchar();
}
或者给key排序之类的,都是可以的。
这是关于map的博客
下面是例题
Babelfish
You have just moved from Waterloo to a big city. The people here speak an incomprehensible dialect of a foreign language. Fortunately, you have a dictionary to help you understand them.
Input
Input consists of up to 100,000 dictionary entries, followed by a blank line, followed by a message of up to 100,000 words. Each dictionary entry is a line containing an English word, followed by a space and a foreign language word. No foreign word appears more than once in the dictionary. The message is a sequence of words in the foreign language, one word on each line. Each word in the input is a sequence of at most 10 lowercase letters.
Output
Output is the message translated to English, one word per line. Foreign words not in the dictionary should be translated as “eh”.
Sample Input
dog ogday
cat atcay
pig igpay
froot ootfray
loops oopslay
atcay
ittenkay
oopslay
Sample Output
cat
eh
loops
Hint
Huge input and output,scanf and printf are recommended.
#include
#include
#include
#include
#include
#include
using namespace std;
map<string,string>mp; //定义一个map容器mp
int main(int argc,char const*argv[]){
char english[10],foreign[10];
char str[25];
while(gets(str)&&str[0]!='\0'){ //输入词典:每次循环一个词条,有空行:输入结束
sscanf(str,"%s%s",english,foreign); //sscanf()以固定类型为输入源
mp[foreign]=english; //在map中以字符串下标数组的形式输入
}
while(gets(str)&&str[0]!='\0'){ //每次循环处理一个要查询的外语单词
sscanf(str,"%s",foreign);
if(mp[foreign]!="\0"){ //如果查询的到,就输出英语
cout<<mp[foreign]<<endl;
}
else //查询不到则输出"eh"
printf("eh\n");
}
return 0;
}
然后是vector和map结合的一道题。
Ananagrams
Most crossword puzzle fans are used to anagrams — groups of words with the same letters in different
orders — for example OPTS, SPOT, STOP, POTS and POST. Some words however do not have this
attribute, no matter how you rearrange their letters, you cannot form another word. Such words are
called ananagrams, an example is QUIZ.
Obviously such definitions depend on the domain within which we are working; you might think
that ATHENE is an ananagram, whereas any chemist would quickly produce ETHANE. One possible
domain would be the entire English language, but this could lead to some problems. One could restrict
the domain to, say, Music, in which case SCALE becomes a relative ananagram (LACES is not in the
same domain) but NOTE is not since it can produce TONE.
Write a program that will read in the dictionary of a restricted domain and determine the relative
ananagrams. Note that single letter words are, ipso facto, relative ananagrams since they cannot be
“rearranged” at all. The dictionary will contain no more than 1000 words.
Input
Input will consist of a series of lines. No line will be more than 80 characters long, but may contain any
number of words. Words consist of up to 20 upper and/or lower case letters, and will not be broken
across lines. Spaces may appear freely around words, and at least one space separates multiple words
on the same line. Note that words that contain the same letters but of differing case are considered to
be anagrams of each other, thus ‘tIeD’ and ‘EdiT’ are anagrams. The file will be terminated by a line
consisting of a single ‘#’.
Output
Output will consist of a series of lines. Each line will consist of a single word that is a relative ananagram
in the input dictionary. Words must be output in lexicographic (case-sensitive) order. There will always
be at least one relative ananagram.
Sample Input
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
Sample Output
Disk
NotE
derail
drIed
eye
ladder
soon
#include
#include
#include
#include
#include
#include
#include
using namespace std;
vector<string>word;
vector<string>ans;
map<string,int>dict;
string getkey(string s){ //把字符串里面字母全部转换为小写,再按升序进行排序
string key=s;
for(int i=0;i<key.length();i++){
key[i]=tolower(key[i]); //把字符大写转小写函数
}
sort(key.begin(),key.end()); //此时的key已经是按字母顺序并且全为小写的字符串了
return key;
}
int main(int argc,char const*argv[]){
string s;
while(cin>>s&&s[0]!='#'){
string key=getkey(s); //让输入的每一个字符串都转换为key
dict[key]++; //如果有变形词,那么dict[key]就不为一
word.push_back(s); //把一开始输入的字符串放进vector容器word中
}
for(int i=0;i<word.size();i++){ //进行循环找出非变形词
if(dict[getkey(word[i])]==1)
ans.push_back(word[i]); //如果是非变形词就放入vector容器ans中
}
sort(ans.begin(),ans.end()); //将ans按字母顺序进行排列
for(int i=0;i<ans.size();i++){
cout<<ans[i]<<endl; //输出
}
return 0;
}
set,set一般是和迭代器一起使用,使用的话要有
#include
using namespace std;
set<类型>名称
set是有自动排序功能的,如果要使用这个功能的话需要一个重载函数决定排序的方式,举个例子,如果是结构体的话:
struct spot{
int x,y;
};
//重载函数
bool operator<(const spot& ai,const spot& bi){
return ai.x>bi.x;
}
复杂一点的话就:
struct spot{
int vans[55][55];
}p;
//重载函数
bool operator<(const spot& a,const spot& b){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(a.vans[i][j]<b.vans[i][j]) return true;
if(a.vans[i][j]>b.vans[i][j]) return false;
}
}
return false;
}
s.size():返回set容器的元素个数;
s.clear():清空set内元素;
set.count(a):返回set内元素a的个数(在set里只能返回1或者0,但是在multiset里可以返回具体数值);
set.insert(a):在set中插入元素a;
set.erase(a):在set中将元素a删除,并且返回指向下一个元素的迭代器;
set.find(a):在set中找到元素a,并返回指向a的迭代器;
set.upper_bound(a):在容器中找到大于a的最小的元素的迭代器,如果不存在则返回set.end();
set.lower_bound(a):在容器中找到大于等于a的最小的元素的迭代器,如果不存在则返回set.end();
使用set迭代器的话定义的形式为:
set<类型>::iterator 名字
如果定义一个set
的迭代器,进行操作:
set<int>s;
set<int>::iterator it;
it=s.begin(); //令it指向s内的第一个元素
it++; //it指针向后移一位
int a;
it=s.upper_bound(a); //让it指向大于a的最小的元素
it--; //指针往前移一位
这里的it相当于指针,给it赋值的操作其实就是让it这个指针指向各种我们需要的数。
迭代器遍历:
//迭代器遍历
for(it=s.begin();it!=s.end();it++){
cout<<*it<<endl; //因为it相当于指针,所以输出的时候要取地址
}
it是指针,如果想输出it指向的数,则需要对it这个指针进行取地址。
具体可以看这个博客,连每个操作的时间复杂度都有给出:指路