【笔记】STL

大部分内容来自sys大佬的课件+网络,侵删
【复制粘贴真爽】

算法

算法库
#include<algorithm>

序列操作

区间一般是左闭右开

unique 去重

复杂度O(n)

返回值是指针,指向去重后序列最后一项的后一项
重复的元素会被放到后面
只能去掉连续的重复元素,要先排序

next_permutation 排列

复杂度O(n)(单次操作!)。

把序列变成下一个排列。
如果已经是最后一个排列则返回false。

reverse 反转

复杂度O(n)
该函数可以反转一段序列的元素;
例如reverse(a+2,a+5)就可以反转数组a从下标2到下标4的元素了。
从来没用过。。

swap

swap(a,b) 交换a,b ab的类型需要相同

排序操作

sort 排序

复杂度平均O(NlogN)

sort(a,a+n)即可对数组a进行升序排序操作。
可以加一个比较函数cmp,实现按照给定关键字和顺序排序
sort(a+1,a+n+1,cmp)

stable_sort

复杂度O(NlogN)
用法基本和sort相同
内部实现为归并排序,稳定排序

最大最小

min/max

min(a,b) 返回较小值
可以重载<运算符或者传入cmp min(a,b,cmp)

据说手写文本替换更快

#define max(a,b) ((a) > (b) ? (a) : (b))
#define min(a,b) ((a) < (b) ? (a) : (b))

min_element/max_element

复杂度O(r-l)。
返回区间最大/最小值的指针。
*p = min_element(a+l,a+r);
没用过。。

二分查找

lower_bound/upper_bound

返回不小于/大于给定值的第一个值的指针。
获取数组下标时,可用
int *p = lower_bound(a, a+6, 4); i = p – a;
则i是数组下标。

binary_search

复杂度O(logN)
在一段升序区间中查找是否存在该元素。
实现了二分查找。
用法:binary_search(a,a+n,val);//val是要查找的值

总结规律:

1、关系到区间的操作一般都是传入指针,而且是左闭右开区间。
2、关系到比较的操作一般都可以传入比较函数。
3、这些算法的速度都是比较快的,因为它们的内部实现加了很多优化。

指针 迭代器有关

指针

int* p 定义一个指针变量,变量名是p,p存储位置
输出 *p 获得p指向的值
lower_bound()的返回值类似指针

&是取址运算符,能够获取某变量的地址

#include<bits/stdc++.h>
using namespace std;
int main(){
    int a[10]={0,11,22,33,44};

    int* p=a;/*等价于 int* p=&a[0];*/
    cout<<p<<endl;//指针存储地址 
    cout<<&p<<endl;//对指针取址,返回指针的地址 
    cout<<*p<<endl;//指针所指向的地址上的值 
    cout<<a+1<<endl;/*等价*/cout<<&a[1];


    int p=lower_bound(a,a+9,44)-a;
    cout<<p<<endl; //下标 

    int p=*lower_bound(a,a+9,44);
    cout<<p<<endl;//数值 


    int* p=lower_bound(a,a+9,44); 
    cout<<p<<endl;//地址 
    cout<<*p<<endl;//数值
    cout<<p-a<<endl;//下标    
}

迭代器

大部分容器都有begin()和end()两个函数,它们返回的是容器的头迭代器和尾迭代器。
要注意的是end()指向的是容器末尾元素的下一个元素,这与STL左闭右开的习惯是一致的。

对于区间相关的函数来说,只要能传入数组的指针就能传入迭代器。
相应地,返回指针的函数(例如unique、lower_bound)在此时就会返回迭代器。

sort一个vector v;
sort(v.begin(),v.end());

重载运算符

在结构体外部重载
struct point{
    int x,y;
};
point operator + (point a,point b){
    return (point){a.x+b.x,a.y+b.y};
}
在结构体内部重载
struct point{
    int x,y;
    point operator + (point b){
        return (point){x+b.x,y+b.y};
    }
};
外部重载 < 用于排序或容器内使用
bool operator < (node a,node b){
    return a.x<b.x;
}

容器

容器的成员函数的调用方法是
容器变量名.函数名(参数1,参数2,…);

string

操作

头文件 < string >
只要包含任意c++头文件(如< iostream >)即可

定义 string s;可以看做一个动态申请内存的char数组s[]

  string s1; //定义一个字符串s1,并初始化为空
  string s2(s1); //用s1初始化s2
  string s3(“value”); //将s3初始化为”value”
  strng s4(n,’c’); //将s4初始化为字符’c’的n个副本

可以直接进行赋值操作:s=“233233”;等号右边可以是字符数组。
可以直接进行字符串加法:string a=s1+s2;
也可以直接用<、>、==等运算符比较字典序大小,可以直接sort按照字典序排序
可以用s[i]访问s的第i号字符(下标从0开始)。
在末尾插入元素 s.push_back(c);
可以对已经使用过的位置直接修改

可以直接用cin>>s的方法直接读入一个字符串。//貌似只能用cin、cout
忽略开头的(制表符、换行符、空格),当再次碰到空字符就停止(并不会读取空字符)。
卡读入的话可以用scanf读入一个字符数组再赋值给string。
getline(cin,s); cin指的是读入流,一般情况下我们直接写cin即可,s是字符串,即我们读入的东西要存放的字符串。可以读取一行(包括空格),会舍弃换行符

函数

s. size()/s.length();   //返回s的长度。
s.push_back(c);     //在再s的最后插入字符c。char类型c
s.empty();          //判断s是否为空。
s.clear();          //清空s。
s.c_str();          //返回对应相等的字符数组。
s.substr(pos,len);  //返回起始于pos下标处长度为len的子串。可以用strcpy赋值给char数组
s.insert(pos,c);        //在pos处插入字符或字符串c string类型c
s.erase(pos,len);       //删除s.substr(pos,len)。
s.find(str);            //在s中寻找str这个字符串,返回该串起始位置的迭代器,复杂度O(s.size())(听说比手动查找快……) //迭代器不会用。。。
#include<bits/stdc++.h>
using namespace std;
int main(){
    string s;
    s="abcdefghijklmn";
    cout<<s.size()<<endl;
    char a='o';
    s.push_back(a);
    s.push_back('o');
    cout<<s<<endl;
    char ss[5000];
    //printf("%s",s); 会gg 
    printf("%s\n",s.c_str());
    cout<<s.substr(1,2)<<endl;
    string p="a";
    s.insert(1,"a");
    s.insert(1,p);
    cout<<s<<endl;
    s.erase(0,2);
    cout<<s<<endl;

    s.push_back('a'); 插入字符‘a’
    char a='c';
    s.push_back(a); 插入字符变量a,内容是字符‘c'

    char a='c';
    s[0]=a; //把s[0]修改为‘c’

    s[0]='b'//把s[0]修改为‘b’
}

pair

不如struct结构体

定义于< utility >,不需要特意包含。
pair<类型1,类型2>p;
类型1,类型2可以是int、double、string等,
也可以是自定义的结构体或pair<…,…>;
<>里的东西就是模板,类型1、类型2就是模板参数;
pair有两个成员变量first、second,类型分别对应类型1,类型2。
可以用make_pair(a,b)创建一个first和second分别是a、b的pair,类型自动识别。
重载了 < 运算符,优先比较first。
(是在是比较鸡肋……)

stack 栈

需要包含头文件< stack >

push(x) //把对应类型的x压入栈
top()       //访问(不删除)栈顶元素
pop()       //删除栈顶元素
empty() //判断栈是否空
size()      //返回栈的元素数量

queue

需要包含头文件< queue >

push(x) //把x压入队列
front() //访问(不删除)队首元素
back()      //访问(不删除)队尾元素
pop()       //删除队首元素
empty() //判断队列是否空
size()      //返回队列的元素数量

priority_queue

操作

头文件是< queue >
实际上是一个封装的堆。
priority_queue<类型>q;
需要类型重载了 < 运算符。
默认是大根堆
可以通过取相反数来构建伪·小根堆。
或者多加两个模板参数:
priority_queue<type,vector<type>,greater<type> > Q;
注意最后两个> >之间有个空格,否则可能会被编译器认成>>。
插入和删除的复杂度都是O(logN)的。

函数

push(x) //把x插入堆
top()       //访问(不删除)堆顶元素
pop()       //删除堆顶元素
empty() //判断堆是否空
size()      //返回堆的元素数量
(没有clear()……)

deque

操作

头文件< deque >
可以从队首和队尾进行插入和删除操作。
还可以访问队中元素。
可以用d[i]访问元素。
用于SPFA的SLF优化,不过因为常数巨大,慎重优化

函数

push_back(x)/push_front(x)  //把x压入后/前端
back()/front()              //访问(不删除)后/前端元素
pop_back() pop_front()      //删除后/前端元素
empty() //判断deque是否空
size()      //返回deque的元素数量
clear()     //清空deque
支持通过sort(d.begin(),d.end())进行排序。

vector

头文件< vector >
定义:vector<类型>v;
一个不定长数组,动态倍增式申请内存
同样可以用v[i]访问第i号元素。
可以v1=v2进行赋值操作。

push_back(x)    //把x压入后端
back()/front()  //访问(不删除)后/前端元素
pop_back()  //删除后端元素
empty()     //判断vector是否空
size()          //返回vector的元素数量
resize(x)       //重置vector的大小为x
clear()         //清空vector
支持通过sort(v.begin(),v.end())进行排序
貌似可以对已经申请了内存的地址直接修改赋值 v[i]=58;

set multiset

头文件< set >
set<类型> s;
类似于数学上的集合,因为内部的元素都是唯一的。
内部实现是红黑树!(因此需要类型重载 < 运算符)
所以插入和查询都是O(logN)的!
set常数比较大

函数

insert(x);  //在集合中插入x
find(x);    //寻找x,返回指向x位置的迭代器,不存在返回s.end();复杂度O(logN) 可以通过判断是否等于s.end()判断是否存在,迭代器不是很会用,所以emmm
count(x);   //统计x的个数,相当于查找;由于元素是唯一的,所以只会返回01。
erase(x);   //查找x并将其删除。复杂度O(logN)
clear();    //清空集合。
size();     //返回集合元素数
lower_bound(x)/upper_bound(x);      //二分查找……

multiset
比起set只是元素可以重复而已
count函数更实用了。
erase会删掉一群……

map multimap

头文件< map >
map<类型1(key),类型2(value)>m;
类型1(key)重载 < 运算符,类型2(value)不用
类型2(value)与类型1(key)的元素一一绑定。
支持通过m[xxx]=yyy插入或访问元素,xxx是类型1,yyy是类型2。
要注意的是如果m中没有xxx这个元素那么m[xxx]会返回0(其他类型是空容器)。
听说map< xxx,bool >可以替代set……

find(x);    //寻找x,返回指向x位置的迭代器,不存在返回m.end();复杂度O(logN)
count(x);   //统计x的个数,相当于查找;由于元素是唯一的,所以只会返回0和1。
erase(x);   //查找x并将其删除。复杂度O(logN)
clear();    //清空映射。
size();     //返回映射元素数
lower_bound(x)/upper_bound(x);         //二分查找……

multimap……
key可重的映射,用法与map差不多……
那么如果重复的话m[xxx]返回的是哪一个呢?
你以为multimap还会这么良心地给你[]么……
听说这东西比multiset有用??

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值