目录
STL是Standard Template Library的简称,中文名标准模板库,惠普实验室开发的一系列软件的统称。在C++标准中,STL被组织为下面的13个头文件:<algorithm>、<deque>、<functional>、<iterator>、<array>、<vector>、<list>、<forward_list>、<map>、<unordered_map>、<memory>、<numeric>、<queue>、<set>、<unordered_set>、<stack>和<utility>。
一、vector
vector 是向量类型,它可以容纳许多类型的数据,如若干个整数,所以称其为容器。vector 是C++ STL的一个重要成员,使用它时需要包含头文件:
#include<vector>;
1.vector 的初始化
vector<int> a(10); //定义了10个整型元素的向量(尖括号中为元素类型名,它可以是任何合法的数据类型),但没有给出初值,其值是不确定的。
vector<int> a(10,1); //定义了10个整型元素的向量,且给出每个元素的初值为1
vector<int> a(b); //用b向量来创建a向量,整体复制性赋值
vector<int> a(b.begin(),b.begin+3); //定义了a值为b中第0个到第2个(共3个)元素
int b[7]={1,2,3,4,5,9,8};
vector<int> a(b,b+7); //从数组中获得初值
2.vector对象的常用操作
a.push_back(5); //在a的最后一个向量后插入一个元素,其值为5
a.pop_back(); //删除a向量的最后一个元素
a[i]; //返回a的第i个元素,当且仅当a[i]存在
a.back(); //返回a的最后一个元素
a.front(); //返回a的第一个元素
a.clear(); //清空a中的元素
a.empty(); //判断a是否为空,空则返回ture,不空则返回false
a.assign(b.begin(), b.begin()+3); //b为向量,将b的0~2个元素构成的向量赋给a
a.assign(4,2); //是a只含4个元素,且每个元素为2
a.erase(a.begin()+1,a.begin()+3); //删除a中第1个(从第0个算起)到第2个元素,也就是说删除的元素从a.begin()+1算起(包括它)一直到a.begin()+3(不包括它)
a.insert(a.begin()+1,5); //在a的第1个元素(从第0个算起)的位置插入数值5,如a为1,2,3,4,插入元素后为1,5,2,3,4
a.insert(a.begin()+1,3,5); //在a的第1个元素(从第0个算起)的位置插入3个数,其值都为5
a.insert(a.begin()+1,b+3,b+6); //b为数组,在a的第1个元素(从第0个算起)的位置插入b的第3个元素到第5个元素(不包括b+6),如b为1,2,3,4,5,9,8,插入元素后为1,4,5,9,2,3,4,5,9,8
a.size(); //返回a中元素的个数;
a.capacity(); //返回a在内存中总共可以容纳的元素个数
a.resize(10); //将a的现有元素个数调至10个,多则删,少则补,其值随机
a.resize(10,2); //将a的现有元素个数调至10个,多则删,少则补,其值为2
a.reserve(100); //将a的容量(capacity)扩充至100,也就是说现在测试a.capacity();的时候返回值是100.这种操作只有在需要给a添加大量数据的时候才显得有意义,因为这将避免内存多次容量扩充操作(当a的容量不足时电脑会自动扩容,当然这必然降低性能)
a.swap(b); //b为向量,将a中的元素和b中的元素进行整体性交换
a==b; //b为向量,向量的比较操作还有!=,>=,<=,>,<
3.顺序访问vector方式
(1)向向量a中添加元素
1、
vector<int> a;
for(int i=0;i<10;i++)
a.push_back(i);
2、也可以从数组中选择元素向向量中添加
int a[6]={1,2,3,4,5,6};
vector<int> b;
for(int i=1;i<=4;i++)
b.push_back(a[i]);
3、也可以从现有向量中选择元素向向量中添加
int a[6]={1,2,3,4,5,6};
vector<int> b;
vector<int> c(a,a+4);
for(vector<int>::iterator it=c.begin();it<c.end();it++)
b.push_back(*it);
4、也可以从文件中读取元素向向量中添加
ifstream in("data.txt");
vector<int> a;
for(int i; in>>i)
a.push_back(i);
5、【误区】
vector<int> a;
for(int i=0;i<10;i++)
a[i]=i;
//下标只能用于获取已存在的元素,而现在的a[i]还是空的对象
(2)从向量中读取元素
1、通过下标方式读取
int a[6]={1,2,3,4,5,6};
vector<int> b(a,a+4);
for(int i=0;i<=b.size()-1;i++)
cout<<b[i]<<" ";
2、通过遍历器方式读取
int a[6]={1,2,3,4,5,6};
vector<int> b(a,a+4);
for(vector<int>::iterator it=b.begin();it!=b.end();it++)
cout<<*it<<" ";
4.常用算法
使用时需要包含头文件:
#include<algorithm>
sort(a.begin(),a.end()); //对a中的从a.begin()(包括它)到a.end()(不包括它)的元素进行从小到大排列
reverse(a.begin(),a.end()); //对a中的从a.begin()(包括它)到a.end()(不包括它)的元素倒置,但不排列,如a中元素为1,3,2,4,倒置后为4,2,3,1
copy(a.begin(),a.end(),b.begin()+1); //把a中的从a.begin()(包括它)到a.end()(不包括它)的元素复制到b中,从b.begin()+1的位置(包括它)开始复制,覆盖掉原有元素
find(a.begin(),a.end(),10); //在a中的从a.begin()(包括它)到a.end()(不包括它)的元素中查找10,若存在返回其在向量中的位置
二、pair
使用pair类型需包含头文件<utility>,定义如下:
类模板:template<class T1,class T2> struct pair
参数:T1是第一个值得数据类型,T2是第二个值的数据类型。
1、创建和初始化
//创建
pair<string, int> word_count; // 创建一个空对象 word_count, 两个元素类型分别是string和int类型
pair<string, vector<int> > line; // 创建一个空对象line,两个元素类型分别是string和vector类型
//定义时初始化
pair<string, string> author("James","Joy"); // 创建一个author对象,两个元素类型分别为string类型,并默认初始值为James和Joy。
pair<string, int> name_age("Tom", "18");
pair<string, int> name_age2(name_age); // 拷贝构造初始化
//typedef简化
typedef pair<string,string> Author;
Author proust("March","Proust");
2、pair对象操作
pair<int ,double> p1;
p1.first = 1;
p1.second = 2.5;
cout<<p1.first<<' '<<p1.second<<endl;
//输出结果:1 2.5
利用make_pair函数生成pair对象
pair<int, double> p1;
p1 = make_pair(1, 1.2);
cout << p1.first << p1.second << endl;
pair类型数据利用sort函数排序时默认根据first的数值排序。
三、stack
c++stack(堆栈)是一个容器的改编,它实现了一个先进后出的数据结构(FILO)。
stack 模板类的定义在<stack>头文件中。stack 模板类需要两个模板参数,一个是元素类型,一个容器类型,但只有元素类型是必要的,在不指定容器类型时,默认的容器类型为deque。
定义stack对象:
stack<int>s1;
stack<string>s2;
stack的基本操作:
1.入栈:s.push(x);
2.出栈:s.pop().注意:出栈操作只是删除栈顶的元素,并不返回该元素。
3.访问栈顶元素:s.top();
4.判断栈空:s.empty().当栈空时返回true。
5.访问栈中的元素个数:s.size();
四、queue
queue类是C++提供的一个队列的功能的容器适配器,实现了一个FIFO(先入先出)的数据结构。queue模版类的定义在<queue>头文件中。
queue与stack模版非常类似,queue模版也需要定义两个模版参数,一个是元素类型,一个是容器类型,元素类型是必要的,容器类型是可选的,默认为deque类型。
定义queue对象
queue<int>q1;
queue<double>q2;
queue的基本操作
1.入队:如q.push(x):将x元素接到队列的末端;
2.出队:如q.pop() ,弹出队列的第一个元素,并不会返回元素的值;
3.访问队首元素:如q.front();
4.访问队尾元素,如q.back();
5.访问队列中的元素个数,如q.size();
6.判断队列空:q.empty(),当队列为空时返回true。
优先队列priority_queue
在<queue>头文件中,还定义了一个非常有用的模版类priority_queue(优先队列),优先队列与队列的差别在于优先队列不是按照入队的顺序出队,而是按照队列中元素的优先权顺序出队(默认为大者优先即大顶堆,也可以通过指定算子来指定自己的优先顺序)。
priority_queue模版类有三个模版参数,元素类型,容器类型,比较算子。其中后两个都可以省略,默认容器为vector,默认算子为less,即小的往前排,大的往后排(出队时序列尾的元素出队)。
定义priority_queue对象的示例代码如下:
priority_queue<int >q1;
priority_queue<pair<int,int> >q2;
priority_queue<int,vector<int>,greater<int> >q3;//定义小的先出队
priority_queue的基本操作均与queue相同。
定义比较算子的方法:重载比较运算符。优先队列试图将两个元素x 和y 代入比较运算符(对less 算子,调用x<y,对greater 算子,调用x>y),若结果为真,则x 排在y 前面,y 将先于x 出队,反之,则将y 排在x 前面,x 将先出队。
五、algorithm
<algorithm>头文件是C++的标准模版库中最重要的头文件之一,提供了大量基于迭代器的非成员模板函数。
不修改内容操作
for_each(Iterator begin,Iterator end,Function fn)对容器指定范围中的每个元素调用指定函数
find(begin,end,const T& val)返回指定范围内第一个值等于val的元素的迭代器,若没有该元素则返回end
find_if(begin,end,pred)返回指定范围内第一个值满足给定条件pred的元素的迭代器,若没有该元素则返回end
count(begin,end,const T& val)返回指定范围内值等于给定值的元素的个数
count_if(begin,end,pred)返回指定范围内满足给定条件的元素的个数
search(begin1,end1,begin2,end2)返回范围[begin1,last1)中第一个与范围[begin2,end)等价的子范围首元素迭代器
修改内容操作
unique(begin,end,pred) 移去指定范围中的所有连续重复元素,仅仅留下每组等值元素中的第一个元素,返回值是去重之后范围的尾地址 ,m=unique(a,a+n)-a,m即为去重后元素个数。
copy(begin,end,result) 将[begin,endl)范围内元素复制到result开始的范围中并返回其尾迭代器。
swap(a,b)交换对象的值
move(begin,end,result) 将[begin,endl)范围内元素移动到result开始的范围中并返回其尾迭代器。
remove(begin,end,val) 将[begin,endl)范围内值等于val的元素移动到result开始的范围中并返回其尾迭代器。
replace(begin,end,old,new)将[begin,end)范围内值等于old的元素赋值为new。
reverse(begin,end)将指定范围内元素反=反转排序。
rotate(begin,middle,end) 循环移动范围[begin,end)中的元素,使middle成为新的首元素
排序操作
is_sorted | 检测指定范围是否已排序 |
is_sorted_until | 返回最大已排序子范围 |
nth_element | 部分排序指定范围中的元素,使得范围按给定位置处的元素划分 |
partial_sort | 部分排序 |
partial_sort_copy | 拷贝部分排序的结果 |
sort(begin,end,cmp) | 对指定范围进行排序,默认升序排列,可定义比较函数cmp |
stable_sort | 稳定排序 |
查找操作
binary_search(begin,end,val,cmp) | 判断范围中是否存在值等价于给定值的元素 |
equal_range(begin,end,val,cmp) | 返回给定范围中所有值等于给定值的元素组成的子范围的边界(等价于以下两个函数返回值组成的pair类型,该范围应先排序或由val划分) |
lower_bound(begin,end,val,cmp) | 返回指向范围中第一个值大于或等于给定值的元素的迭代器 |
upper_bound(begin,end,val,cmp) | 返回指向范围中第一个值大于给定值的元素的迭代器 |
最大最小操作
is_permutation(begin1,end1,begin2) | 判断一个序列是否是另一个序列的一种排序 |
lexicographical_compare(begin1,end1,begin2,end2) | 比较两个序列的字典序,序列1字典序小于序列2则返回true |
max(a,b) | 返回两个元素中值最大的元素 |
max_element(begin,end,cmp) | 返回给定范围中值最大的元素 |
min(a,b) | 返回两个元素中值最小的元素 |
min_element(begin,end,cmp) | 返回给定范围中值最小的元素 |
minmax(a,b) | 返回两个元素中值最大及最小的元素(pair) |
minmax_element(begin,end,cmp) | 返回给定范围中值最大及最小的元素(pair) |
next_permutation(begin,end,cmp) | 返回给定范围中的元素组成的下一个按字典序的排列 |
prev_permutation(begin,end,cmp) | 返回给定范围中的元素组成的上一个按字典序的排列 |
划分操作
is_partitioned(begin,end,pred) | 检测某个范围是否按指定谓词(Predicate)划分过 |
partition(begin,end,pred) | 将某个范围划分为两组,返回指向第二组首元素的迭代器 |
partition_copy(begin,end,result_true,result_false,pred) | 拷贝指定范围的划分结果到相应区域,返回拷贝后两组序列的尾迭代器 |
partition_point(begin,end,pred) | 返回指向被划分范围的划分点的迭代器 |
stable_partition(begin,end,pred) | 稳定划分,两组元素各维持相对顺序 |
集合操作
includes(begin1,end1,begin2,end2) | 判断第二个集合是否是另一个集合的子集,集合应先排序 |
inplace_merge(begin,middle,end) | 合并两个连续的有序序列,组成一个新的有序序列 |
merge(begin1,end1,begin2,end2,result) | 合并两个有序序列至一个新的有序序列result中,返回新序列的尾迭代器,下同。 |
set_difference(begin1,end1,begin2,end2,result) | 获得两个有序集合的差集A-B |
set_intersection(begin1,end1,begin2,end2,result) | 获得两个集合的交集AB |
set_symmetric_difference(begin1,end1,begin2,end2,result) | 获得两个集合的对称差 |
set_union(begin1,end1,begin2,end2,result) | 获得两个集合的并集 |
堆操作
C++中的堆,要基于向量使用。操作基于三个函数std::make_heap
,std::push_heap
,std::pop_heap
,并且要配合push_back
与pop_back
使用。
1.make_heap(begin,end,cmp) 根据给定范围及可选的比较函数建立堆。默认建立大顶堆,对int类型,可以在第三个参数传入greater<int>() 得到小顶堆。
2.push_heap(begin,end,cmp) 把指定区间的最后一个元素插入到堆中。只能基于已经是堆的容器添加数据,先将元素插入容器尾部再插入堆中。
3.pop_heap(begin,end,cmp) 弹出堆顶元素, 将其放置于区间末尾,重新建立堆。只能基于已经是堆的容器添加数据,将堆顶元素弹出至容器尾部后弹出容器。
4.sort_heap(begin,end,cmp) 堆排序算法,通过反复调用pop_heap弹出堆顶元素直到堆为空来得到有序序列,必须作用于堆。
5.is_heap(begin,end,cmp) 检测给定范围是否满足堆结构
6.is_heap_until(begin,end,cmp)检测给定范围中满足堆结构的最大子范围
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
void print(int x)
{
cout << x << ' ';
}
int main()
{
vector<int>v;
for(int i=10;i>0;i--)
v.push_back(i);
cout << "创建小顶堆:" << endl;
make_heap(v.begin(), v.end(),greater<int>());
for_each(v.begin(), v.end(), print);
cout <<endl;
cout <<"向堆中添加元素4:"<<endl;
v.push_back(4);
push_heap(v.begin(), v.end(),greater<int>());//新元素先推入向量在推入堆
for_each(v.begin(), v.end(), print);
cout <<endl;
cout <<"弹出堆顶元素:" << endl;
pop_heap(v.begin(), v.end(),greater<int>());
for_each(v.begin(), v.end(), print);
v.pop_back();//堆顶元素先推出堆,再推出向量
cout <<endl<< "进行堆排序:" << endl;
sort_heap(v.begin(), v.end(),greater<int>());
for_each(v.begin(), v.end(), print);
return 0;
}
其他
结构体定义
struct Point {
int x, y;
Point(int x=0,int y=0):x(x),y(y){}
};
Point a, b(3, 6);
结构体内定义构造函数Point,参数x,y默认为0,x(x),y(y)把成员变量x初始化为参数x,成员变量y初始化为参数y。定义变量Point a,b(3,6)分别调用了Point()(即Point(0,0))和Point(3,6)。也可以写成Point(int x=0,int y=0){this->x=x;this->y=y;},其中this为指向当前对象的指针。
操作符重载
Point operator+(const Point &a, const Point &b)
{
return Point(a.x + b.x, a.y + b.y);
}
ostream& operator<<(ostream &out, const Point &a)
{
out << "(" << a.x <<" "<< a.y << ")";
return out;
}
cout << a + b << endl;
代码中重新定义了+和<<操作符,使结构体可以直接相加,输出。
模板
template <typename T>
T sum(T *begin, T *end)
{
T *p = begin;
T ans = 0;
for (p; p != end; p++)
{
ans = ans + *p;
}
return ans;
}
Point a, b(3, 6), p[] = { Point(2,5),Point(3,2),Point(4,2) };
cout << sum(p, p + 3) << endl;
模板函数可以对任意已定义+操作符的类型求和。
template <typename T>
struct Point {
T x, y;
Point(T x = 0, T y = 0) :x(x), y(y) {}
};
template <typename T>
Point<T> operator + (const Point<T>& A, const Point<T>& B)
{
return Point<T>(A.x + B.x, A.y + B.y);
}
template <typename T>
ostream& operator << (ostream &out, const Point<T>& p) {
out << "(" << p.x << "," << p.y << ")";
return out;
}
为结构体Point定义模板,可以同时使用double,int型Point。