STL
目录索引
- STL
- 概述
- 容器
- Vector: 动态数组,运行时根据需要改变数组大小。
- Stack:基本的数据结构之一,特点是“先进后出”。
- Queue:队列:基本的数据结构之一,特点是“先进先出”。
- priority_queue(优先队列):以某种排序准则(默认为less)管理队列中的元素
- Deque:双端队列(deque模拟动态数组)
- List:双向链表。它的内存空间不必连续,通过指针来进行数据的访问,高效率地在任意地方删除和插入,插入和删除操作是常数时间。
- 迭代器(iterator):可遍历STL容器内全部或部分元素的对象;指出容器中的一个特定位置
- Set:set用二叉搜索树实现,集合中的每个元素只出现一次,且是排好序的。
- Multiset:多重集合
- Map:使用平衡二叉树管理元素
- next_permutation(): 求“下一个”排列组合。
概述
STL六大部件: 容器、分配器、算法、迭代器、适配器、仿函数
- 容器: 用来存放数据
- Sequence Container(循序式容器):排列次序取决于插入时机和位置
array(c++11)、vector、 stack、queue、deque、 priority_queue、list - Associative Container(关联式容器):排列次序取决于特定准则
set/multimap 、map /multimap
- 适配器: 一种接口类,为已有的类提供新的接口,目的是简化、约束、使之安全、隐藏或者改变被修改类提供的服务集合;(三种类型的适配器)
- 容器适配器:用来扩展7种基本容器,它们和顺序容器相结合构成栈、队列和优先队列容器
- 迭代器适配器(反向迭代器、插入迭代器、IO流迭代器)
- 函数适配器(函数对象适配器、成员函数适配器、普通函数适配器)
- 算法: 计算数据
- 迭代器:访问数据的式(算法使用其访问容器内大数据)
- 仿函数 :类似于函数的功能
六大部件的使用实例:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<functional>
#include<vector>
using namespace std;
int main ()
{
int ia[6]={27,210,12,47,109,83};
vector<int,allocator<int> > vi(ia,ia+6);
cout<<count_if(vi.begin(),vi.end(),not1(bind2nd(less<int>(),40)));
return 0;
}
容器
容器区间都是左闭右开的;
Vector: 动态数组,运行时根据需要改变数组大小。
- 以数组形式存储,内存空间是连续的,索引可以在常数时间内完成。
- 但是在中间进行插入和删除操作,会造成内存块的拷贝。
功能 | 例子 | 说明 |
---|---|---|
定义int型数组 | vector a; | 默认初始化,a为空 |
vector b(a); | a有100个值为0的元素 | |
vector a(100, 6); | 100个值为6的元素 | |
定义string型数组 | vector a(10,”null”); | 10个值为null的元素 |
vector vec(10,”hello”); | 10个值为hello的元素 | |
vectorb(a.begin(), a.end()); | b是a的复制 | |
定义结构型数组 | struct point { int x, y;};vector a; | a用来存坐标 |
#include<bits/stdc++.h>
using namespace std;
int main(){
vector <int> table; //模拟圆桌
int n, m
while(cin >> n >> m)
{
table.clear();
for(int i=0; i<2*n; i++) table.push_back(i); //初始化
int pos = 0; //记录当前位置
for(int i=0; i<n; i++) //赶走n个
{
pos = (pos+m-1) % table.size();
//圆桌是个环,取余处理
table.erase(table.begin() + pos);
//赶走坏人,table人数减1
}
int j = 0;
for(int i=0; i<2*n; i++)
{ //打印预先安排座位
if(!(i%50) && i) cout<<endl;
//50个字母一行
if(j<table.size() && i==table[j])
{//table留下的都是好人
j++;
cout<<"G";
}
else
cout<<"B";
}
cout<<endl<<endl; //留一个空行
}
return 0;
}
Stack:基本的数据结构之一,特点是“先进后出”。
- push(value)-将元素压栈
- top()-返回栈顶元素的引用,但不移除
- pop()-从栈中移除栈顶元素,但不返回
实例:Text Reverse
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
char ch;
scanf("%d",&n);
getchar();
while(n--){
stack<char> s;
while(true){
ch = getchar(); //一次读入一个字符
if(ch==' '||ch=='\n'||ch==EOF){
while(!s.empty()){
printf("%c",s.top()); //输出栈顶
s.pop(); //清除栈顶
}
if(ch=='\n'||ch==EOF) break;
printf(" ");
}
else s.push(ch); //入栈
}
printf("\n");
}
return 0;
#include <stdio.h>
#include <stack>
#include <algorithm>
using namespace std;
int main()
{
double n,m;
char c;
while(~scanf("%lf",&n))
{
c=getchar();
if(c=='\n' &&n==0) break;
stack<double>s;
s.push(n);
scanf("%c",&c);
while(~scanf("%lf",&n))
{
if(c=='*')
{
m=s.top();
m*=n;
s.pop();
s.push(m);
}
if(c=='/')
{
m=s.top();
m/=n;
s.pop();
s.push(m);
}
if(c=='+')
s.push(n);
if(c=='-')
s.push(0-n);
if(getchar()=='\n')
break;
c=getchar();
}
double sum=0;
while(!s.empty())
{
sum+=s.top();
s.pop();
}
printf("%.2lf\n",sum);
}
return 0;
}
Queue:队列:基本的数据结构之一,特点是“先进先出”。
- push(e)-将元素置入队列
- front()-返回队列头部元素的引用,但不移除
- back()-返回队列尾部元素的引用,但不移除
- pop()-从队列中移除元素,但不返回
实例:ACboy needs your help again!
#include<bits/stdc++.h>
using namespace std;
int main(){
int t,n,temp;
cin>>t;
while(t--){
string str,str1;
queue<int>Q;
stack<int>S;
cin>>n>>str;
for(int i=0; i<n; i++){
if(str=="FIFO"){ //队列
cin>>str1;
if(str1=="IN"){
cin>>temp; Q.push(temp);
}
if(str1=="OUT"){
if(Q.empty()) cout<<"None"<<endl;
else{
cout<<Q.front()<<endl;
Q.pop();
}
}
}
else{ //栈
cin>>str1;
if(str1=="IN"){
cin>>temp; S.push(temp);
}
if(str1=="OUT"){
if(S.empty()) cout<<"None"<<endl;
else {
cout<<S.top()<<endl;
S.pop();
}
}
}
}
}
return 0;
}
priority_queue(优先队列):以某种排序准则(默认为less)管理队列中的元素
- push(e)-根据元素的优先级将元素置入队列
- top()-返回优先队列头部最大的元素的引用,但不移除
- pop()-从栈中移除最大元素,但不返回
- empty() -队列是否为空
priority_queue <int,vector,less > p; //降序
priority_queue <int,vector,greater > q;//升序
Deque:双端队列(deque模拟动态数组)
- deque的元素可以是任意类型T,但必须具备赋值和拷贝能力(具有public拷贝构造函数和重载的赋值操作符)
- 必须包含的头文件#include
- deque支持随机存取
- deque支持在头部和尾部存储数据
- deque不支持capacity和reserve操作
构造、拷贝和折构
赋值操作
非变动操作
元素存取
List:双向链表。它的内存空间不必连续,通过指针来进行数据的访问,高效率地在任意地方删除和插入,插入和删除操作是常数时间。
list和vector的优缺点正好相反,它们的应用场景不同:
(1)vector:插入和删除操作少,随机访问元素频繁;
(2)list:插入和删除频繁,随机访问较少
- push_back()
- size()
- max_size() 存放最多的元素的个数,只要内存足够,就能够一直分配
- front() 返回第一个元素的引用,不检查元素是否存在
- back() 返回最后一个元素的引用,不检查元素是否存在
插入元素
移出元素
迭代器(iterator):可遍历STL容器内全部或部分元素的对象;指出容器中的一个特定位置
双向迭代器
可以双向行进,以递增运算前进或以递减运算后退、可以用==和!=比较。list、set和map提供双向迭代器
随机存取迭代器
除了具备双向迭代器的所有属性,还具备随机访问能力。可以对迭代器增加或减少一个偏移量、处理迭代器之间的距离或者使用<和>之类的关系运算符比较两个迭代器。vector、deque和string提供随机存取迭代器stack、queue、priority_queuqe不支持迭代器
所有容器都提供两种迭代器:
- container::iterator以“读/写”模式遍历元素
- container::const_iterator以“只读”模式遍历元素
begin():返回一个迭代器,指向第一个元素
end():返回一个迭代器,指向最后一个元素之后
Set:set用二叉搜索树实现,集合中的每个元素只出现一次,且是排好序的。
Multiset:多重集合
- 多重集合和set最大的区别就是,它可以插入重复的元素,
- 如果删除的话,相同的也一起删除了;
- 如果查找的话,返回该元素的迭代器的位置,若有相同,返回第一个元素的地址;
Map:使用平衡二叉树管理元素
- 元素包含两部分(key,value),key和value可以是任意类型
- 必须包含的头文件#include
- 根据元素的key自动对元素排序,因此根据元素的key进行定位很快,但根据元素的value定位很慢
- 不能直接改变元素的key,可以通过operator []直接存取元素值
- map中不允许key相同的元素,multimap允许key相同的元素
其中map可以是下列形式:
map<key,value> 一个以less(<)为排序准则的map,
map<key,value,op> 一个以op为排序准则的map
Map的赋值:
第一种方式:
第二种方式:
第三种方式:
next_permutation(): 求“下一个”排列组合。
例如三个字符{a, b, c}组成的序列,next_permutation()能按字典序返回6个组合:abc,acb,bac,bca,cab,cba。
给定n个数字,从1到n,要求输出第m小的序列。
输入:数字n和m组成,1 <= n <= 1000,1 <= m <= 10000。
输出:输出第m小的序列。
#include<bits/stdc++.h>
using namespace std;
int a[1001];
int main(){
int n, m;
while(cin>>n>>m){
for(int i=1; i<=n; i++)
a[i] = i; //生成一个字典序最小的序列
int b = 1;
do{
if(b == m) break;
b++;
}while(next_permutation(a+1,a+n+1)); //注意第一个是a+1, 最后一个是a+n
for(int i=1; i<n; i++) //输出第m大的字典序
cout << a[i] << " ";
cout << a[n] << endl;
}
return 0;
}