一、vector
1.简介
有些时候想开一个数组,但是却不知道应该开多大长度的数组合适,因为我们需要用到的数组可能会根据情况变动。这时候我们就需要用到动态数组。
所谓动态数组,也就是不定长数组,数组的长度是可以根据我们的需要动态改变的。动态数组的实现也不难,但是在 C + + C++ C++里面有已经写好的标准模板库 S T L STL STL,实现了集合、映射表、栈、队列等数据结构和排序、查找等算法。我们可以很方便地调用标准库来减少我们的代码量。
C
+
+
C++
C++中动态数组写作vector
,
C
C
C语言中没有标准库,这也是为什么参加比赛推荐用
C
+
+
C++
C++而不用
C
C
C的原因。
2.定义
#include <vector>
using namespace std;
int main()
{
return 0;
}
使用
S
T
L
STL
STL的动态数组需要首先在代码的开头引入这个头文件,并不要忘记using namespace std;
vector<T> vec;
T
T
T表示我们所定义的数组存储数据的类型。它可以是int
,double
这样的基本数据类型,可以是typedef
之后的代词,也可以是自定义的结构体类型,甚至可以是其他的
S
T
L
STL
STL类型。
typedef long long ll;
vector<int> a;
vector<double> b;
vector<ll> c;
vector<node> d;
vector<vector<ll> >e;
一开始定义好的动态数组的长度为 0 0 0,代表一个空的数组。
3.基本操作
(1)插入元素到尾部push_back()
vector<int> vec; //{}
vec.push_back(1);//{1}
vec.push_back(2);//{1,2}
vec.push_back(3);//{1,2,3}
(2)访问以及修改某一元素的值
cout<<vec[2]<<endl;//3
vec[2]=10;
cout<<vec[2]<<endl;//10
注意动态数组默认的下标是从 0 0 0开始的。除此以外,所有的操作和普通的数组是一样的。
(3)获取数组长度size()
cout<<vec.size()<<endl;//3
for(int i=0;i<vec.size();i++)
cout<<vec[i]<<endl;
//{1,2,10}
这里的size()
也可以用length()
代替,它们这个使用条件下完全相同
(4)删除末尾元素
vec.pop_back();//{1,2}
vec.pop_back();//{1}
(5)清空数组
vec.push_back(10);//{1,10}
vec.push_back(20);//{1,10,20}
vec.clear(); //{}
但需要注意的是,clear()
只清空了数组,但没有释放掉动态数组的空间
vector<int> x;
{
vector<int> New;
x.swap(New);
}
如果要释放掉vector
的空间,那么最好的方法是创建一个空的数组,并将其替换。
(6)初始化
int n=10;
vector<int> vec(n,1);
这里给数组预先分配了长度为 n n n的空间,并将这 n n n个元素全部设为初始值 1 1 1。
二、set
1.简介
集合是一个特殊的数据结构,在集合中不会出现同样的元素。集合中的元素是按一定的顺序排列的,默认按照从小到大的顺序。我们可以通过迭代器来顺序访问每一个元素。
如果想用可重复的集合,那么可以使用multiset
,它们的实现方式都是红黑树,支持的函数也都差不多,这里不再赘述。
2.定义
set<T> s;
T
T
T表示我们所定义的数组存储数据的类型。它可以是int
,double
这样的基本数据类型,可以是typedef
之后的代词,也可以是自定义的结构体类型,甚至可以是其他的
S
T
L
STL
STL类型。
#include <set>
using namespace std;
typedef long long ll;
struct node
{
ll x,y;
bool operator < (const node &a) const
{
if(x==a.x)
return y<a.y;
return x<a.x;
}
};
set<int> a;
set<double> b;
set<ll> c;
set<node> d;
set<vector<ll> >e;
但需要注意的是,如果定义的集合是建立在结构体上的,因为涉及到set
的有序性,所以必须重载运算符。
一开始定义好的集合的长度为 0 0 0,代表一个空的集合。
3.基本操作
(1)插入元素insert()
set<int> s; //{}
s.insert(2);//{2}
s.insert(1);//{1,2}
s.insert(3);//{1,2,3}
s.insert(3);//{1,2,3}
- 向
set
中插入元素时,会自动排序。 - 向
set
中插入已有元素时,插入不会产生任何效果。
(2)查找某一元素count()
由于set
是有序的,所以可以很快速的查询出某一个元素是否在集合中。
//{1,2,3}
if(s.count(5))
cout<<"5 is in the set."<<endl;
else
cout<<"5 is not in the set."<<endl;
(3)获取集合大小size()
//{1,2,3}
cout<<s.size()<<endl;//3
(4)删除某一个元素
s.erase(10);//{1,2}
s.earse(8);//{1,2}
删除集合中的某一个元素,如果此元素不在集合中,那么删除不会产生任何效果。
(5)查找某一元素find()
//{1,2,10,20}
if(s.find(10)!=s.end())
cout<<"10 is in the set."<<endl;
find()
函数可以查找一个元素并返回其对应的迭代器,如果集合中没有该元素,那么就会返回end()
。
(6)清空集合clear()
//{1,2}
s.insert(10);//{1,2,10}
s.insert(20);//{1,2,10,20}
s.clear(); //{}
但需要注意的是,与vector
不同的是,set
的clear()
不仅删除了元素,还清空了内存。
(7)遍历
//{1,2,10,20}
for(set<int>::iterator it=s.begin();it!=s.end();it++)
{
cout<<(*it)<<" ";
}
//1 2 10 20
因为集合使用的不是连续空间,而是使用了迭代器,所以我们需要使用迭代器iterator
来遍历集合。
注意s.begin()
和s.end()
并不是整数,而是迭代器类型,所以it!=s.end()
不能改成it<s.end()
。
遍历的结果是按照定义的顺序排列的。
三、map
1.简介
两个非空集合A与B间存在着对应关系 f f f,而且对于 A A A中的每一个元素 a a a, B B B中总有唯一元素 b b b与它对应,就将这种对应为从A到B的映射,记作 f : A → B f:A\rightarrow B f:A→B。其中, b b b称为元素 a a a在映射 f f f下的像,记作: b = f ( a ) b=f(a) b=f(a)。 a a a称为 b b b关于映射 f f f的原像。集合 A A A中所有元素的像的集合称为映射 f f f的值域,记作 f ( A ) f(A) f(A)。
比如集合{‘A’,‘B’,‘C’}与{1,2,3}可以构成如下映射:
2.定义
map<T1,T2> mp;
T
1
,
T
2
T1,T2
T1,T2表示我们所定义的数组存储数据的类型,它们可以是相同的也可以是不同的。它可以是int
,double
这样的基本数据类型,可以是typedef
之后的代词,也可以是自定义的结构体类型,甚至可以是其他的
S
T
L
STL
STL类型。
#include <map>
using namespace std;
typedef long long ll;
map<int,int> a;
map<double,int> b;
map<ll,ll> c;
map<node> d;
map<vector<ll> >e;
一开始定义好的动态数组的长度为 0 0 0,代表一个空的数组。
3.基本操作
(1)插入一对映射insert()
map<string,int> mp; //{}
mp.insert(pair<string,int>("A",3));//{(A,3)}
mp.insert(pair<string,int>("B",1));//{(A,3),(B,1)}
mp.insert(pair<string,int>("C",2));//{(A,3),(B,1),(C,2)}
mp.insert(make_pair("D",4)); //{(A,3),(B,1),(C,2),(D,4)}
mp.insert(make_pair("A",4)); //{(A,3),(B,1),(C,2),(D,4)}
因为映射描述的是一种关系,涉及到两个元素,所以这里用pair
这一类型类帮助我们插入。pair
表示一个二元组,它的类型被<>
定义。可以用如上两种方式创造一个pair
变量。pair
有两个域first
和second
,访问方式如下:
pair<string,int> temp=make_pair("A",4);
cout<<temp.first<<" "<<temp.second<<endl;
如果插入的原像已有对应的像,那么这样的插入就是无效的,并不会替代原来的值。
(2)访问以及修改某一对映射的值
//{(A,3),(B,1),(C,2),(D,4)}
cout<<mp["B"]<<endl;//1
mp["B"]=10;
//{(A,3),(B,10),(C,2),(D,4)}
cout<<mp["B"]<<endl;//10
mp["E"]=2;
//{(A,3),(B,10),(C,2),(D,4),(E,2)}
访问map
和访问数组几乎一致,修改的方式也是一样的,直接赋值即可。如果访问的原像并没有对应的像,那么它就会创建一个新的映射。
(3)获取映射对个数size()
cout<<mp.size()<<endl;//5
注意一个像可以有很多个原像,但一个原像不可以有多个像。所以注意这里是映射对的数量,而不是像的数量。
(4)查询某一个原像count()
//{(A,3),(B,10),(C,2),(D,4),(E,2)}
if(mp.count("A"))
cout<<mp["A"]<<endl;
如果一个原像没有对应的像,那么直接访问会报错。所以要先用count()
查询像是否存在之后再访问。
(5)遍历映射
for(map<string,int>::iterator it=mp.begin();it!=mp.end();it++)
{
cout<<(*it).first<<" "<<(*it).second<<endl;
}
因为映射使用的不是连续空间,而是使用了迭代器,所以我们需要使用迭代器iterator
来遍历映射。
注意s.begin()
和s.end()
并不是整数,而是迭代器类型,所以it!=s.end()
不能改成it<s.end()
。
遍历的结果是按照定义的顺序排列的。
(6)清空映射clear()
mp.clear();//{}
map
的clear()
不仅删除了元素,还清空了内存。
四、作业
1.vector
P3613 【深基15.例2】寄包柜
P2141 [NOIP2014 普及组] 珠心算测验
2.set
P1152 欢乐的跳
P5143 攀爬者
3.map
P1102 A-B 数对
P6402 [COCI2014-2015#2] UTRKA