码迷,mamicode.com
首页 > 其他好文 > 详细

信STL,得永生(STL大法好)

时间:2019-01-25 17:48:54      阅读:205      评论:0      收藏:0      [点我收藏+]

标签:手写堆   语句   detail   容量   删除元素   rate   put   结构   ext   

STL大法好!

当然,是不可能得永生的,但它可以延长你的在役时间

最近总结了一些STL的神奇用法,C++的STL作弊器一样,简直kongbu......

所以说,我们一起来看看STL的用法吧!

目录:

1.vector
2.stack
3.queue&priority_queue
4.string
5.map
6.set&multiset
7.list
8.pair
9.bitset
10.algorithm

 

当然,这只会是一个大致的讲解,不会非常详细

 


 

vector

vector,就是不定长数组,内部基于倍增的思想,当数组中有了n个数时(nvector的内存数),vector会申请一个2n的连续空间,把数据拷过去,再释放原来的空间。当数组中的元素<=n/4时,就释放掉一半的空间。也就是说,你想要多少空间就给你多少。

vector支持随机访问,可以直接用如a[i]的方式访问,效率O(1)。

vector声明

 

1 #include <vector>    //头文件
2 vector<int> a;          //int数组
3 vector<int> k[233]   //第一维长233,第二维变化
4 struct vec_{
5     int x;
6     char name[100]
7 }
8 vector<rec> stru_vec  //自定义的类也能保存在vector中

 

vector语法

 1 一般的调用:名称.函数名();
 2 size:返回vector的长度。
 3 empty:返回一个bool值,表示vector是否为空。
 4 clear:清空vector
 5 begin/end:返回指向第一个/最后一个元素的迭代器。(*a.begin() 等价于a[0])
 6 front/back:front返回vector的  第一个元素,等价于*a.begin()/a[0]
 7             back 返回vector的最后一个元素,等价于*--a.end()/a[a.size()-1]
 8 push_back/pop_back:
 9 push_back(int x)将x插入到vector的尾部
10 pop_back()删除vector的最后一个元素(不返回值)
11 erase(l,r) 删除[l,r)中的元素(也就是从l到r-1的所有元素)
12 erase(it) 删除位于迭代器it位置的元素

 

迭代器:

vector区中我们额外讲一下迭代器。

迭代器是STL里面的指针。

一个保存有int数据vector的迭代器声明:

1 vector<int>::iterater it

 我们可以用迭代器遍历整个vector:

for(vector<int>::iterater it=a.begin();it!=a,end();++it)
  cout<<(*it)<<" ";

vector也支持随机插入:

a.insert(it,x);

在迭代器it处插入x,但vector毕竟不是链表,它的时间复杂度为O(n)。

 


 

stack

stack,也就是栈,大家对栈这种数据结构一定不陌生了,而且手写很容易实现 ,但STL中的stack是不定长的

#include <stack>  //定义栈要用的头文件
stack<int> a;   //int类的栈
/*也可以传结构体型啦~*/

stack语法

将元素x放入栈顶: s.push(x);
获得栈顶元素: s.top();
弹出栈顶元素: s.pop();
检查stack是否为空,为空返回1,否则返回0: s.empty();
s.size()/s.empty 用法,用途与stack一样。

 


 

queue&priority_queue

queue是队列,先进先出的队列。大家对队列也一定不陌生了,而且手写很容易实现 。

没错,STL中的queue还是不定长的

/*定义方式其实就是把stack哪里的stack改为queue啦~*/

queue的语法

将元素x插入队尾: q.push(x);
获得队首元素: q.front()
弹出队首元素: q.pop();
front/back/empty/size还是和stack一样用啦~

 priority_queue

申请n个存放int类型变量的priority_queue:
priority_queue<int>q;

所以priority_queue有什么用呢?

优先队列,其顶部是权值最大的元素,你插入后,它会自动把优先队列里的元素按照权值排好。(其实就是大根堆啦~)

会了priotity_queue,再也不用手写堆啦

priority_queue的语法:

1 priority_queue队首元素最大啦~
2 将元素x插入优先队列: q.push(x);
3 获得队首的元素: q.top()
4 弹出队首的元素: q.pop();
5 让队首元素最小: periority_queue<int> >queue2;

(合并果子是很常见的堆题,那么priority_queue也适合解这种题啦~)


 

string

作为蒟蒻的我,实在所学不多,再者,string这个东西,肥肠好用,而且包含的函数极多,我这里恐怕写不下,我只能稍微提几点,而且不甚详细,请大家想深究的自行baiduORgoogle一下,顺手贴上一个网址,是一位大佬的博客,总有几篇不错的,这里贴几篇比较详细的,大家可以参阅。

CSDN  cnblog 

 string就是字符串,(废话)他需要头文件<cstring>调用(<string>也可以)

它相当于一个字符数组,长度是4294967295(?)

它同样可以用s[i]调用。

string的语法:

int capacity()              //返回当前容量
int max_size()              //返回string对象中可存放的最大字符串的长度
int size()                  //返回当前字符串的大小
int length()                //返回当前字符串的长度
bool empty()                //当前字符串是否为空
void resize(int len,char c);//把字符串当前大小置为len,并用字符c填充不足的部分

差不多先这样啦......


 

map

map可不要把它理解成数据结构图了,它和图有着本质的区别。映射。map相当于一个数组,但是它的下标可以是各种各样的类,并且只有你申请过的下标才会被储存。

例如你申请一个这样的map: map<string,int> mp; 就可以写 mp["litbleorz"]=233; 这样的语句。  (莫名提到某大佬)

注意:map的复杂度是 O(nlogn) 的。

map的声明:

1 #include <map>      //头文件准备
2 /*然后:*/
3 map<int,int> mp     //话说以int为下标和数组有什么区别

map的语法:

 1 数x元素出现过了几次(其实只有0和1):
 2 mp.count(x)
 3 一个元素是否在map中: 
 4 mp.find(x) (但好像速度比count 略慢)
 5 删除元素(迭代器删除: mp.erase(it); 或元素删除:mp.erase(x);)
 6 插入元素:insert(key_type,value_type)
 7 //也就是“下标”和元素的值
 8 /*当然,map作为一个可以当数组实用的东东,可以用mp[i]调用元素的。*/
 9 size/empty/clear/begin/end:
10 //老东西了,分别指:
11 /*元素个数,是否为空,清空,首迭代器,尾迭代器*/

 

set&multiset

setmultiset的唯一区别只在set会自动去重,multiset不会

他俩的内部实现都基于红黑树,支持函数也基本相同。

所以我们就拿set来举栗子吧。

头文件就不说了。

声明:
set<int> s;
multiset<int> c;
set<rec/*A_struct*/> ss;
但是,set&multiset的类型必须定义了<运算符
插入元素: S.insert(x);                     //O(logn)
删除元素x(参数也可是迭代器): S.erase(x);
返回元素x的迭代器: S.find(x)
查找set内部第一个大于等于x的元素,返回迭代器:lower_bound(x)
查找set内部第一个严格大于x的元素,返回迭代器:upper_bound(x)
size/empty/clear:略。
s.count(x) 数集合中元素x的个数。

大家注意,在multiset中,直接erase(x),会将所有元素x删除!!只需删除一个的要用S.erase(S.find(x));


 

list

list,就是传说中的链表(手写也很简单,模拟链表更简单)

介绍一下STL中的list

1 头?件: #include<list>
2 1.新建: list<int> lis;
3 2.最后一个元素: lis.back() ;第一个元素:lis.front() 。
4 3.在最后插入一个元素: lis.push_back(); ,最前面:lis.push_front();
5 4.删除最后一个元素: lis.pop_back(); ,最前面:lis.pop_front();
6 5.翻转所有元素: lis.reverse();
7 6.在指定迭代器位置后面插入一个元素:lis.insert(it,x); // 时间复杂度O(1) 

那啥也就这些......


 

pair

pair是将2个数据组合成一个数据,当需要这样的需求时就可以使用pair,如STL中的map就是将key和value放在一起来保存。另一个应用是,当一个函数需要返回2个数据的时候,可以选择pair。 pair的实现是一个结构体,主要的两个成员变量是first&second,而且可以直接用p.first/p.second调用变量(话说自己不能定义结构体吗)

pair的声明:
pair<int, double> p1;         //使用默认构造函数
pair<int, double> p2(1,1.1);  //用给定值初始化
pair<int, double> p3(p2);     //拷贝构造函数

这里直接贴一个pair的链接,我认为讲得比较详细(其实完全可以自己找)


 

bitset

bitset是一个二进制数。

声明:

bitset<10000> bit;  定义了一个10000位的bitset

为什么要用bitset?位运算不是更好吗?

unsigned long long都不够用时,bitset就来大显身手了,它的大小是很大的。

bitset相当于是一个数组,上面的bit就是一个10000的数组,你自然可以手动编一个bitset ,就每一位每一位地位运算,但那样的复杂度是O(n)的,但bitset的复杂度是O(n/32)的,因为它是将每32位压入了一个int里面(自然,这样也可以压入long long,你可以自己试着手写,这样复杂度就是O(n/64)的了,但奉劝大家没有必要,因为我看见一位大佬手写bitset300多行......)

同样,bitset和普通的数一样,都可以执行这些内容:

~bit      //取反
&,|,^,>>,<<  //与普通数的作用相同
==,!=    //是否相等
[]运算符    // bit[i]表示bit的第i位,可以取赋值。
count()    // 有多少个1
any/none  //若bit值为0(所有位为0),bit.any()=false;bit.none()=true;若bit值不为0(也就是至少一位为1),bit.any()=true;bit.none()=false;
bit.set()   将bit所有位变为1
bit.set(i,x)    将bit第i位变为x,即bit[i]=x;
bit.reset()   把bit所有位归0
bit.reset(i)    把bit第i位归0
bit.flip()      即bit=~bit
bit.flip(i)       将bit第i位取反。

algorithm 

algorithm算法库,作弊库

数学

1 max(a,b),min(a,b) :返回a,b中的较大/小值,a,b必须是同种类型的元素
2 abs(x) :取绝对值。
3 fabs(x) :取实数的绝对值时,比abs精度更高。
4 swap(a,b) :交换a,b的值,也可以交换数组/STL,交换数组/STL时,由于是交换指针,所以是 O(1) 的。

sort
排序,左闭右开,复杂度 O(nlog n) ,比手写快排快多了。
排序数组: sort(a+1,a+1+n);
排序STL: sort(a.begin(),a.end());
自定义比较函数:

1 bool cmp(int x,int y) {return x>y;}
2 int main()
3 {
4 sort(a+1,a+1+n,cmp); //从?到?排序
5 return 0;
6 }

reverse

区间翻转,左闭右开,复杂度 O(n) ,比手动翻转快。
数组:reverse(a+1,a+1+n);
STL:reverse(a.begin(),a.end());

next_permutation

求出全排列的字典序下一个排列,例如a,b,c组成的排列,按照字典序有如下排列:

abc,acb,bac,bca,cab,cba

若没有下个排列,则返回值为false。
同理也有prev_permutation,用来求上一个排列

for(int i=1;i<=n;++i) a[i]=i;
do{
    for(int i=1;i<=n;++i) printf("%d" a[i]);
    putchar(\n);
}while(!next_permutation(a+1,a+1+n));

lower_bound

二分查找,寻找指定区间内第一个大于等于给定权值的值,并返回指针或迭代器,复杂度 O(nlog n) ,比手写二分查找快。

要查找的区间必须按从小到大顺序有序,才能保证返回正确的结果。

还有一个upper_bound,用于查找第一个严格大于给定权值的元素的位置。

for(int i=1;i<=n;++i) a[i]=i;
int k=lower_bound(a+1,a+1+n,3)-a;
cout<<k<<endl;

unique

去重,原理是将所有重复的元素都堆在序列最后?,然后假装它们不存在,返回尾指针/迭代器。要求序列按从小到大有序。

例如你想将 a 这个int类型的数组去重:

int len=unique(a+1,a+1+n)-a-1;

恐怖

希望大家合理利用STL!

信STL,得永生(STL大法好)

标签:手写堆   语句   detail   容量   删除元素   rate   put   结构   ext   

原文地址:https://www.cnblogs.com/oierwa-Luogu/p/10320389.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!