vector
vector被翻译为向量也称作变长数组
vector的定义
使用vector要记得加上头文件 #include<vector>
vector<typename> name;
vector<int> vi;
vector<double> vi;
vector<char> vi;
vector<node> vi;//node可以是结构体
vector是一个类似于int a[]的整数数组,而vector是一个类似于string a[]的字符串数组
它是基于倍增的思想的变长数组
基本常用的一些方法
clear()清空
resize()改变大小
push_back()在尾部添加元素
pop_back()在尾部删除元素
empty()测试是否为空
vector之间可以直接赋值或者作为函数的返回值
push_back()和pop_back()无需改变数组长度,自动会增加和减小数组长度
push_back(x)
在vi的元素末尾添加一个元素x
for(int i=0;i<5;i++)
{
vi.push_back(i);
}
for(int i=0;i<vi.size();i++)
{
cout<<vi[i]<<" "; //0 1 2 3 4
}
vector可以直接赋值,可以通过下标直接访问
#include <bits/stdc++.h>
using namespace std;
int main()
{
vector<int> vi;
vector<int> b;
for(int i=0;i<5;i++)
{
vi.push_back(i);
}
b=vi;
for(int i=0;i<b.size();i++)
{
cout<<b[i]<<" ";
}
return 0;
}
size
返回vector中元素的个数
for(int i=0;i<5;i++)
{
vi.push_back(i);
}
cout<<vi.size()<<endl; //5
clear
清空vector数组中的全部元素
for(int i=0;i<5;i++)
{
vi.push_back(i);
}
vi.clear();//清空了
cout<<vi.size()<<endl;//长度0
return 0;
empty()
判断vector是否为空
for(int i=0;i<5;i++)
{
vi.push_back(i);
}
cout<<vi.empty()<<endl;//0
vi.clear();//清空了
cout<<vi.size()<<endl;//0
cout<<vi.empty()<<endl;//1 因为调用了clear
大家想想empty这个函数和前面的那个函数有相同的作用?
back() 返回vector里的最后一个元素
front() 返回vector里的第一个元素
for(int i=0;i<5;i++)
{
vi.push_back(i);
}
cout<<vi.front()<<endl;//0
cout<<vi.back()<<endl;//4
pop_back()
删除vector尾元素
for(int i=0;i<5;i++)
{
vi.push_back(i);
}
vi.pop_back();//删除最后一项
for(int i=0;i<vi.size();i++)
{
cout<<vi[i]<<" ";//0 1 2 3
}
vector的遍历
1.通过下标方式遍历
for(int i=0;i<5;i++)
{
vi.push_back(i);
}
for(int i=0;i<vi.size();i++)//通过下标方式遍历
{
cout<<vi[i]<<" ";//0 1 2 3 4
}
2.通过迭代器遍历
vector<typename>::iterator it可以把它看做类似于指针的东西
vi[i]和(vi.begin()+i)是等价的
vi.begin()和vi.end()是左开右闭的end()表示的是尾元素的下一个
迭代器支持++,--的操作
迭代器不支持it<end()写法,因此循环条件只能用it !=vi.end()
for(vector<int>::iterator it=vi.begin();it!=vi.end();it++)
{
cout<<*it<<" ";//0 1 2 3 4
}
在常用的stl容器中只有vector和string中才允许使用vi.begin+整数 这种写法
insert()
向vector的任意迭代器it处插入一个元素x
注意第一个参数必须是迭代器
for(int i=0;i<5;i++)
{
vi.push_back(i);
}
vi.insert(vi.begin()+2,8);//在下标为2的地方插入8
for(int i=0;i<vi.size();i++)
{
cout<<vi[i]<<" ";//0 1 8 2 3 4
}
vector和algorithm里面的函数的应用
//reverse() 倒置 是在algorithm里面的函数
//12345
reverse(vi.begin(),vi.end());
for(vector<int>::iterator it=vi.begin();it!=vi.end();it++){
cout<<*it<<" ";//5,4,3,2,1
}
cout<<endl;
//sort()排序默认是从小到大排 还可以任意排序后面讲
sort(vi.begin(),vi.end());
for(vector<int>::iterator it=vi.begin();it!=vi.end();it++){
cout<<*it<<" ";//1,2,3,4,5
}
string
string类的定义
定义string类的方式跟基本数据类型相同,只需要在string后跟上变量名即可
string str;
如果要初始化,可以直接给string类进行赋值
string str="hello";
string类的访问
直接通过下标访问
string str="abcdef";
for(int i=0;i<str.length();i++){
cout<<str[i];
}
如果要读入和输出字符串只能用cin和cout
cin>>str;
cout<<str;
如果读入带有空格等等的字符串
getline(cin,str);
如果要用printf输出string类型
printf("%s",str.c_str());
通过迭代器访问
for(string::iterator it=str.begin();it!=str.end();it++){
cout<<*it;
}
string和vector 一样,支持直接对迭代器进行加减某个字数str.begin()+i
string类可以直接进行加法,可以将两个string类拼接起来
string类可以直接比较大小 是按字典序排的
length() size() 返回string的长度
string str="abcdef";
cout<<str.length()<<endl;//6
cout<<str.size()<<endl;//6
insert()
insert(pos,string) 在pos号位置插入字符串string
string str1="abc";
string str2="ddd";
str1.insert(1,str2);
cout<<str1<<endl;//adddbc
这里和之前讲的vector对比一下vector第一个参数的迭代器而string的是位置
insert(it,it2,it3) it为原字符串欲插入的位置 it2和it3为待插字符串的首位
//insert(it,it2,it3) it为原字符串欲插入的位置 it2和it3为待插字符串的首尾迭代器
string str3="abcde";
string str4="fghi";
str3.insert(str3.begin()+3,str4.begin(),str4.begin()+2);
cout<<str3<<endl;//abcfgde
erase()
erase() 有两种用法一种是删除单个元素另一种是删除一个区间的所有元素
删除单个元素 erase(it) 用于删除单个元素 it为要删除的元素的迭代器
// 删除单个元素 erase(it) 用于删除单个元素 it为要删除的元素的迭代器
string s1="abcdef";
s1.erase(s1.begin()+3);
cout<<s1<<endl;//abcef
删除一个区间内的所有元素
str.erase(first,last) first为要删除区间的其实迭代器,last为需要删除的末尾迭代器的下一个地址
str.erase(pos,length) pos为要删除的起始地址 length为要删除的字符个数
//删除一个区间内的所有元素
//str.erase(first,last) first为要删除区间的其实迭代器,last为需要删除的末尾迭代器的下一个地址
string s2="abcdef";
s2.erase(s2.begin(),s2.begin()+4);
cout<<s2<<endl;//ef
//str.erase(pos,length) pos为要删除的起始地址 length为要删除的字符个数
string s3="abcdef";
s3.erase(2,4);
cout<<s3<<endl;//ab
clear()
清空string中的数据
s3.clear();
cout<<s3<<endl;
cout<<s3.length();
find()
str.find(str2) 当str2是str的子串时,返回其在str中第一次出现的位置,如果str2不是str的子串返回-1
str.find(str2,pos)从str的pos号位开始匹配str2
//str.find(str2) 当str2是str的子串时,返回其在str中第一次出现的位置,如果str2不是str的子串返回-1
string ss1="abcdefabc";
string ss2="abc";
int pos=ss1.find(ss2);
cout<<pos<<endl;//0
//str.find(str2,pos)从str的pos号位开始匹配str2
int pos1=ss1.find(ss2,3);
cout<<pos1<<endl;//6
int pos2=ss1.find("xyz");
cout<<pos2<<endl;//-1
stack
大家刚学完数据结构是不是每次用栈和队列都很麻烦还要建链表…stl真的很方便帮我们都写好了直接用。。。。 懒狗的福音哈哈
stack是栈一种先进后出的容器,理解就是书从上往下堆,如果想拿下面的书必须先把上面的书拿开
要使用必须加头文件 #include
stack的定义
stack<typename> name
push
将元素压入栈
top()
取出栈顶元素
pop
弹出栈顶元素
stack不能通过下标访问,只能通过top()来取栈顶元素访问
for(int i=0; i<5;i++)
{
st.push(i);
}
cout<<st.top()<<endl;//4
st.pop();
cout<<st.top()<<endl;//3
empty
判断栈是否空
for(int i=0; i<5;i++)
{
st.push(i);
}
cout<<st.empty()<<endl;//0 非空
size
获取stack内的元素
for(int i=0; i<5;i++)
{
st.push(i);
}
cout<<st.empty()<<endl;//0 非空
cout<<st.size()<<endl;//5
判断非空也可以用size
if(st.size()>0)
{
栈非空
}
清空栈
注意栈没有clear()方法只能遍历清空
while(st.size()>0)
{
st.pop();
}
cout<<st.empty()<<endl;//1
cout<<st.size()<<endl;//0
queue 队列是stl中的一个先进先出的容器,理解就是食堂打饭,前面的人打完了先走后面的人接着排队
队列是stl中的一个先进先出的容器,理解就是食堂打饭,前面的人打完了先走后面的人接着排队
queue的定义
queue<typename> name;
typename可以是任意基本数据类型和容器
队列是一种先进先出的限制性数据结构
q.push(x)将x进行入队
queue<int> q;
//q.push(x)将x进行入队
q.push(1);
q.push(2);
q.push(3);
stl中只能通过front()来访问队首元素,或者通过back()来访问队尾元素
queue<int> q;
//q.push(x)将x进行入队
q.push(1);
q.push(2);
q.push(3);
cout<<q.front()<<" "<<q.back()<<endl; //1 3
pop()
令队首元素出对
queue<int> q;
//q.push(x)将x进行入队
q.push(1);
q.push(2);
q.push(3);
cout<<q.front()<<" "<<q.back()<<endl; //1 3
q.pop();
cout<<q.front()<<endl; //2
empty()
empty()检测queue是否为空
queue<int> q;
q.push(1);
q.push(2);
q.push(3);
cout<<q.empty()<<endl;//0
q.size()
返回队列中元素的数量
queue<int> q;
q.push(1);
q.push(2);
q.push(3);
cout<<q.empty()<<endl;//0
cout<<q.size()<<endl;//3
while(q.size()){
q.pop();
}
cout<<q.empty()<<endl;//1
队列的清空
队列也是没有clear()函数的如果想要清空还是得遍历
while(q.size()>0)
{
q.pop();
}
cout<<q.empty()<<endl;//1
cout<<q.size()<<endl;//0
优先队列
priority queue
也就是堆的概念,这里先不讲到时候讲到具体的算法时候再讲
set
set翻译为集合,是一个内部自动有序且不含重复元素的容器
set的定义
set<typename> name;
set<int> vi;
set<double> vi;
set<char> vi;
set<node> vi;//node可以是结构体
set<int> a[100]; //数组里面每个元素都是一个set集合
insert(x) 将x插入set容器中,并自动递增排序和去重
//insert(x) 将x插入set容器中,并自动递增排序和去重
st.insert(4);
st.insert(3);
st.insert(1);
st.insert(2);
//不支持<it.end()的写法
for(set<int>::iterator it=st.begin();it!=st.end();it++){
cout<<*it<<" ";//1 2 3 4
}
set集合的遍历
set只能通过迭代器遍历
除了vector和string之外的stl容器都不支持*(it+i)的访问方式
set内的元素会自动递增排序,且自动去除了重复元素
//不支持<it.end()的写法
for(set<int>::iterator it=st.begin();it!=st.end();it++){
cout<<*it<<" ";//1 2 3 4
}
find(value)
返回set中对应值为value的迭代器
set<int>::iterator it=st.find(3); //查找值为3的元素返回其迭代器
cout<<*it<<endl; //如果查找的元素不存在会返回最后一个元素的迭代器
erase()删除元素
//erase() 有两种用法一种是删除单个元素另一种是删除一个区间的所有元素
//删除单个的方法又有两种
//1.st.erase(it) it为所删元素的迭代器 可以和find连用
//1 2 3 4
st.erase(st.find(3));
for(set<int>::iterator it=st.begin();it!=st.end();it++){
cout<<*it<<" ";//1 2 4
}
cout<<endl;
//2.st.erase(value) value为所删除元素的值
//1 2 4
st.erase(1);
for(set<int>::iterator it=st.begin();it!=st.end();it++){
cout<<*it<<" ";//2 4
}
cout<<endl;
st.insert(4);
st.insert(3);
st.insert(1);
st.insert(2);
//删除整个区间
//1 2 3 4
st.erase(st.find(2),st.end());
for(set<int>::iterator it=st.begin();it!=st.end();it++){
cout<<*it<<" ";//1
}
size()
返回set内的元素个数
//1 2 3 4
cout<<st.size(); //4
clear()
清空st中的所有元素
st.clear();
cout<<st.size();
empty() 判断是否为空
st.clear();
cout<<st.empty()<<endl;//1 true
st.insert(4);
st.insert(3);
st.insert(1);
st.insert(2);
//1 2 3 4
//lower_bound(k) 返回一个迭代器,指向键值不小于k的第一个元素
set<int>::iterator it=st.lower_bound(2);//寻找第一个大于等于2的数
cout<<*it<<endl;//2
//upper_bound(k) 返回一个迭代器,指向键值大于k的第一个元素
it=st.upper_bound(2);
cout<<*it<<endl;//3
map
map的定义
map<typename1,typename2> mp;
map<int,int> mp;
map<string,int> mp;
map<set<int>,string> mp;
map需要确定映射前类型(键key)和映射后类型(值 value) <>内填写两个类型,其中第一个键的类型,第二个是值的类型,
如果是字符串到整形的映射,必须使用string而不用char数组类型
map容器的内元素的访问
通过下标访问
和访问普通数组一样,例如对一个定义为map<char,int> mp的map来说,就可以直接使用mp[‘c’]的方式来访问它对应的整数,map中的键值是唯一的
map<char,int> mp;
mp['c']=1;
mp['c']=2;//1被覆盖
cout<<mp['c']<<endl;//2;
通过迭代器返回
map<typename1,typename2>::iterator it;
map可以使用it->first来访问键,使用it->second来访问值
map内部是由红黑树实现的
map会以键从小到大的顺序自动排序
insert()
添加一个新的pair到map中
map<char,int> mp;
mp['a']=1;
mp['b']=2;
mp['c']=3;
mp.insert(pair<char,int>('d',4));
map<char,int>::iterator it;
for(it=mp.begin();it!=mp.end();it++){
cout<<it->first<<" "<<it->second<<endl;
}
//a 1
//b 2
//c 3
//d 4
pair其实是一个简单的结构体 需要添加#include<utility>
两个元素的结构体
find()
find(key) 返回键值为key的映射迭代器
map<char,int> mp;
mp['a']=1;
mp['b']=2;
mp['c']=3;
map<char,int>::iterator it;
it=mp.find('a');
cout<<it->first<<" "<<it->second<<endl; //a 1
查找一个元素是否出现在map中
map<char,int> mp;
mp['a']=1;
mp['b']=2;
mp['c']=3;
map<char,int>::iterator it;
it=mp.find('a');
if(it!=mp.end()){ //存在
cout<<"存在"<<endl;
}
else{
cout<<"不存在"<<endl;
}
it=mp.find('d');
if(it!=mp.end()){ //不存在
cout<<"存在"<<endl;
}
else{
cout<<"不存在"<<endl;
}
count(key)
返回某个键值的数量
map<char,int> mp;
mp['a']=1;
mp['b']=2;
mp['c']=3;
mp['c']=4;//会覆盖前面的mp['c']的值
cout<<mp.count('c')<<endl; //1
empty()
map<char,int> mp;
mp['a']=1;
mp['b']=2;
mp['c']=3;
cout<<mp.empty()<<endl;//0
erase()
erase()有两种用法 删除单个元素,删除一个区间内的所有元素
mp.erase(it) it为所需要删除元素的迭代器
map<char,int> mp;
mp['a']=1;
mp['b']=2;
mp['c']=3;
map<char,int>::iterator it;
it=mp.find('a');
mp.erase(it);
for(it=mp.begin();it!=mp.end();it++){
cout<<it->first<<" "<<it->second<<endl; //b 2 c 3
}
mp.erase(key) key为欲删除的映射的键
map<char,int> mp;
mp['a']=1;
mp['b']=2;
mp['c']=3;
map<char,int>::iterator it;
mp.erase('b');
for(it=mp.begin();it!=mp.end();it++){
cout<<it->first<<" "<<it->second<<endl;
}
mp.erase 删除一个区间内的所有元素
mp.erase(first,last) 其中first为需要删除的区间的起始迭代器,而last则为所需要删除的区间的末尾迭代器的下一个地址,也即为删除左闭右开的区间
map<char,int> mp;
mp['a']=1;
mp['b']=2;
mp['c']=3;
mp['d']=4;
mp['e']=5;
map<char,int>::iterator it;
it=mp.find('b');
mp.erase(it,mp.end());
for(it=mp.begin();it!=mp.end();it++){
cout<<it->first<<" "<<it->second<<endl; //a 1
}
clear()清空map集合中的所有元素
size()获得map中映射的对数
map<char,int> mp;
mp['a']=1;
mp['b']=2;
mp['c']=3;
mp['d']=4;
mp['e']=5;
map<char,int>::iterator it;
mp.size();
for(it=mp.begin();it!=mp.end();it++){
cout<<it->first<<" "<<it->second<<endl;
}
mp.clear();
cout<<mp.size()<<endl;//0
c++11还有一些新特性如 unordered_map,unordered_set还挺好用的大家了解下
algorithm
需要引入#include
max,min,abs
max(x,y)和min(x,y) 求两个值中的最大值,最小值
abs(x)x必须是整形
int a=3,b=4,c=-5;
cout<<max(a,b)<<endl; //4
cout<<min(a,b)<<endl; //3
cout<<abs(c)<<endl //5;
swap
swap(x,y)交换两个值
int a=3,b=4,c=-5;
swap(a,b);
cout<<a<<endl;//4
cout<<b<<endl;//3
fill()
fill可以把数组或容器中的某一段区间复制为某个值
//清空数组
int ans[100];
fill(ans,ans+100,0);
memset(ans,0,sizeof(ans));//memset是按字节赋值的
next_permutation
重点,蓝桥杯经常考,用了这个函数后就不用DFS写全排列了,很方便
我自己测试的好像是必须要自己先把数据排序了才行。。。你们可以自己试一下
int ans[10]={1,2,3};
do{
printf("%d%d%d\n",ans[0],ans[1],ans[2]);
}while(next_permutation(ans,ans+3));
lower_bound upper_bound
底层原理应该是二分算法,但是如果我们手写二分第一是比较麻烦,第二是有可能出现边界错误,因此调用这个函数还是很香的啊。。。。
lower_bound (first,last,val)在[first,last)范围内值第一个大于等于val元素
upper_bound(first,last,val)在[first,last)范围内值第一个大于val元素的位置
返回值,如果是数组返回的是该位置的指针,如果是容器,返回该位置的迭代器
这里提一下两个指针相减,就是两个地址之间的距离
int ans[10]={1,2,2,3,3,4};
cout<<(lower_bound(ans,ans+10,2)-ans)<<endl; //1
cout<<(upper_bound(ans,ans+10,2)-ans)<<endl; //3
练习题
给你两个集合,计算其并集,即{A} +{B}。
注: 中不允许出现重复元素,但是 {A} 与 {B} 之间可能存在相同元素。
输入格式
输入数据分为三行,第一行有两个数字 n, m(0<n,m<= 10000),分别表示集合 A 和集合 B 的元素个数。后两行分别表示集合 A 和集合 B。每个元素为不超出int范围的整数,每个元素之间用一个空格隔开。
输出格式
输出一行数据,表示合并后的集合,要求从小到大输出,每个元素之间用一个空格隔开。
样例输入1
1 2
1
2 3
样例输出1
1 2 3
样例输入2
1 2
1
1 2
样例输出2
1 2
解答
#include <bits/stdc++.h>
using namespace std;
int main()
{
set<int> st;
int n,m;
cin>>n>>m;
int a;
for(int i=0;i<n;i++)
{
cin>>a;
st.insert(a);
}
for(int i=0;i<m;i++)
{
cin>>a;
st.insert(a);
}
for(set<int>::iterator it=st.begin();it!=st.end();it++)
{
cout<<*it<<" ";
}
return 0;
}
小A快要考托福了,这几天,小A每天早上都起来记英语单词。小B时不时地来考一考蒜头君:小B会询问蒜头君一个单词,如果小A背过这个单词,小A会告诉小B这个单词的意思,不然小A会跟小B说还没有背过。单词是由连续的大写或者小写字母组成。注意单词中字母大小写是等价的。比如"You"和"you"是一个单词。
输入格式
首先输入一个 表示事件数。接下来 n 行,每行表示一个事件。每个事件输入为一个整数 d 和一个单词 word(单词长度不大于 20),用空格隔开。如果 d=0,表示小A记住了 word 这个单词,如果 d=1,表示这是一个 测试,测试小A是否认识单词 word(小B不会告诉蒜头君这个单词的意思)。事件的输入是按照时间先后顺序输入的。
输出格式
对于小B的每次 测试,如果小A认识这个单词,输出一行"Yes", 否则输出一行"No"。
样例输入1
5
0 we
0 are
1 family
0 Family
1 Family
样例输出1
No
Yes
样例输入2
4
1 jisuanke
0 Jisuanke
0 JISUANKE
1 JiSuanKe
样例输出2
No
Yes
解法1map
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin>>n;
map<string,int> mp;
while(n--)
{
int a;
string s;
cin>>a>>s;
for(int i=0;i<s.length();i++)
{
s[i]=tolower(s[i]);
}
if(a==0)
{
mp[s]=1;
}
else{
if(mp[s]==1)
{
cout<<"Yes"<<endl;
}
else{
cout<<"No"<<endl;
}
}
}
return 0;
}
解法二 set
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin>>n;
set<string> st;
while(n--)
{
int a;
string s;
cin>>a>>s;
for(int i=0;i<s.length();i++)
{
s[i]=tolower(s[i]);
}
if(a==0)
{
st.insert(s);
}
else{
if(st.count(s)==1)
{
cout<<"Yes"<<endl;
}
else{
cout<<"No"<<endl;
}
}
}
return 0;
}
1064 朋友数 (20分)
如果两个整数各位数字的和是一样的,则被称为是“朋友数”,而那个公共的和就是它们的“朋友证号”。例如 123 和 51 就是朋友数,因为 1+2+3 = 5+1 = 6,而 6 就是它们的朋友证号。给定一些整数,要求你统计一下它们中有多少个不同的朋友证号。
输入格式:
输入第一行给出正整数 N。随后一行给出 N 个正整数,数字间以空格分隔。题目保证所有数字小于 10
4
。
输出格式:
首先第一行输出给定数字中不同的朋友证号的个数;随后一行按递增顺序输出这些朋友证号,数字间隔一个空格,且行末不得有多余空格。
输入样例:
8
123 899 51 998 27 33 36 12
输出样例:
4
3 6 9 26
#include <bits/stdc++.h>
using namespace std;
int main()
{
set<int> st;
int n,a;
int sum=0;
cin>>n;
while(n--)
{
cin>>a;
sum=0;
while(a)
{
sum+=a%10;
a/=10;
}
st.insert(sum);
}
int num=0;
cout<<st.size()<<endl;
for(set<int>::iterator it=st.begin();it!=st.end();it++)
{
num++;
cout<<*it;
if(num<st.size())
{
cout<<" ";
}
}
return 0;
}