常用STL整理

注:部分陈述来自menci dalao,实在懒得写陈述。
注:蒟蒻整理,有些名词使用不规范,请谅解。

一. 队列(queue) 先进先出的执的排列

STL 在头文件 中提供了先入先出队列 queue。
使用 push() 向队列中加入元素。
使用 front() 获取队首元素(并不删除)。
使用 pop() 删除队首元素。
使用 empty() 判断队列是否为空。
很常用很熟练,就不写代码举例了。

二. 优先队列(priority_queue)

STL 在头文件 中提供优先队列 priority_queue,在任意时间都能取出队列中的最大值。
使用 push() 向优先队列中加入元素,其时间复杂度为O(logn)。
使用 top() 获取优先队列中最大的元素(并不删除),其时间复杂度为O(1)。
使用 pop() 删除优先队列中最大元素,其时间复杂度为O(logn)。
使用 empty() 判断优先队列是否为空。

    priority_queue<T> q;//T为想要定义的类型

也可以定义为优先最小值:

priority_queue< T,vector<T>,greater<T> >q;//注意greater<int>后面要加空格。 否则计算机会当右移运算符.

三. 双队列(deque) 连续存储的指向不同元素的指针所组成的数组

感觉用不到,
具体看链接吧

四. 栈(stack) 后进先出的值的排列

STL 在头文件 提供了后入先出栈 stack。
使用 push() 向栈中加入元素。
使用 top() 获取栈顶元素(并不删除)。
使用 pop() 删除栈顶元素。
使用 empty() 判断栈是否为空。

std::stack<int> s;

bool flag = s.empty();
// flag = true,栈初始为空

s.push(23333);
s.push(66666);

while (!s.empty()) {
    printf("%d\n", s.top());
    s.pop();
}
// 依次输出 66666,23333

一个栈的使用模板:

#include<iostream>
#include<cstdio>
#include<stack>
using namespace std;
stack<int> st;
int a[11];
int main()
{
    for(int i=1;i<=10;i++)
    {
        cin>>a[i];
        st.push(a[i]);//入栈 
    }
    st.pop();//弹栈,  后入先弹
    while(!st.empty())//判断是否为空 
    {
        int k;
        k=st.top();//访问栈顶
        st.pop();//记得弹栈,否则死循环 
        cout<<k;
        if(st.size()<5) //求个数 
        break; 
    } 
} 

比较常用,不再举例。

五. 向量(vector) 连续存储的元素

STL 在头文件 提供了一个可变长的数组 vector,它支持动态的插入、删除操作。
以下代码声明了一个 vector,它的每个元素类型为 int,初始元素数量为 0。

vector<int> v;

以下代码声明了一个 vector,它的每个元素类型为 int,初始元素数量为 n。

std::vector<int> v(n);

vector 提供 begin() 和 end(),分别获取指向第一个元素和最后一个元素之后的迭代器。

需要注意的是,迭代器的头是第0位

以下代码对 v 中的所有元素以升序排序:

std::sort(v.begin(), v.end());

使用 size() 得到 vector 的元素数量,使用 resize() 重新指定 vector 的元素数量。
分别使用 push_back() 和 pop_back() 在 vector 的尾部加入或删除元素,这两个过程的时间复杂度为O(1)O(1)。
使用 insert() 在某个特定的位置插入一个元素,时间复杂度为O(n)。
使用 erase() 删除某个位置的元素,时间复杂度为O(n)。

vector<int> v;
// v.size() = 0

v.push_back(23333);
// v.size() = 1, v = { 23333 }

v.insert(v.begin() + 0, 890);
// v.size() = 2, v = { 890, 23333 }

v.insert(v.begin() + 1, 12345);
// v.size() = 3, v = { 890, 12345, 23333 }

v.erase(v.begin() + 0);
// v.size() = 2, v = { 12345, 23333 }

for (nt i = 0; i < v.size(); i++) {
    printf("%d\n", v[i]);
}
// 依次输出 12345、23333

v.pop_back();
// v.size() = 1, v = { 12345 }

注意,在加入元素时,如果 vector 拥有的内存空间不足以存放欲加入的元素,则 vector 会申请一块新的内存,并将旧数据拷贝过去,这个过程通常花费 O(n)O(n) 的时间。
本蒻用vector不太熟练,所以一遍不会用,怕炸;
但最近有个t,stl跑一跑就a了
题目在这,T1

#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cstdio>
#include<vector>
using namespace std;
vector<string> a;
string aa;
int ans,n;
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)cin>>aa,a.push_back(aa);
    sort(a.begin(),a.end());
    vector<string>::iterator new_end;
    new_end=unique(a.begin(),a.end());
    for(vector<string>::iterator i=a.begin();i!=new_end;i++)ans++;printf("%d\n",ans);
    for(vector<string>::iterator i=a.begin();i!=new_end;i++)cout<<*i<<endl; 
}

六. 映射(map) 由{键,值}对组成的集合

map的用法有好多,可以用来离散化,记录等,它的操作一般应该都是log n的;
比如:根据key值快速查找记录,查找的复杂度基本是Log(N),如果有1000个记录,最多查找10次,1,000,000个记录,最多查找20次。
map < vector,int> q; //映射不定长数组,神奇QAQ ——————T2
关于map的离散化:

再举个例子

#include<iostream>
#include<map>
#include<cstring>
#include<string>
using namespace std;
map<int,string> q;
map<string,int> p;
int main()
{
    q[1]="abcd";
    p["abcd"]=1;
    cout<<q[1];
    cout<<endl;
    cout<<p["abcd"];
}

输出:这里写图片描述
map的用法比较熟了,不举其他例子了。

七. 多重映射(multimap) 允许键对有相等的次序的映射

百度

八. 集合(set) 由节点组成的红黑树,每个节点都包含着一个元素

这里就用代码解释

[set的遍历与两种排序]
#include<iostream>
#include<set>
using namespace std;
int main()
{
    //set<int,greater<int> > s;   ====>从大到小排序 
    set<int> s;.//默认从小到大
    s.insert(5); //第一次插入5,可以插入
    s.insert(1);
    s.insert(6);
    s.insert(3);
    s.insert(5); //第二次插入5,重复元素,不会插入
    set<int>::iterator it; //定义前向迭代器
    //中序遍历集合中的所有元素
    for(it = s.begin(); it != s.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
    return 0;
}
[set结构体重定义]
struct Info
{
    string name;
    double score;
    bool operator < (const Info &a) const // 重载“<”操作符,自定义排序规则
    {
        //按score由大到小排序。如果要由小到大排序,使用“>”即可。
        return a.score < score;
    }
};
int main()
{
    set<Info> s;
    Info info;//开成info[4]也可以

    //插入三个元素
    info.name = "Jack";//info[1].name="Jack"
    info.score = 80;//info[1].score="80"
    s.insert(info);//s.insert(info[1])
    info.name = "Tom";
    info.score = 99;
    s.insert(info);
    info.name = "Steaven";
    info.score = 60;
    s.insert(info);

    set<Info>::iterator it;
    for(it = s.begin(); it != s.end(); it++)
        cout << (*it).name << " : " << (*it).score << endl; 
    return 0;
}
/*
运行结果:
Tom : 99
Jack : 80
Steaven : 60
*/
[set删除与查找]
int main()
{
    set<int> s;
    s.insert(5); //第一次插入5,可以插入
    s.insert(1);
    s.insert(2);
    s.insert(6);
    s.insert(3);
    s.insert(5); //第二次插入5,重复元素,不会插入
    s.erase(3); //删除键值为3的元素 
    set<int>::iterator it;//申请一个迭代器,注意stl迭代器的申请方法
    it = s.find(6); //查找键值为6的元素存不存在 
    if(it != s.end())
        cout << *it << endl;
    else
        cout << "not find it" << endl;
    it = s.find(3);
    if(it != s.end())
        cout << *it << endl;
    else
        cout << "not find it" << endl;

    //查找元素存在的位置 
    int pos2=*s.lower_bound(2);//返回第一个大于等于key_value的定位器(1,2,3,4,5中会返回2;1,3,4,5中会返回3) 
    int pos2_next=*s.upper_bound(2);//返回第一个大于key_value的定位器(1,2,3,4,5中会返回3)
    cout<<pos2<<endl;
    cout<<pos2_next;
    return 0;
}
/* 也可以用下面这种方式查询 
#include <cstdio>
#include <set>
using namespace std;
int main() {
    set <int> s;
    int a;
    for(int i = 0; i < 10; i++)
        s.insert(i);
    for(int i = 0; i < 5; i++) {
        scanf("%d", &a);
        if(!s.count(a)) //不存在
            printf("does not exist\n");
        else
            printf("exist\n");
    }
    return 0;
}//s.count 记录的是元素出现的次数, 因为在集合中, 最多出现一次, 所以可用此查询 
*/
[set重定义比较]
struct mycomp
{ //自定义比较函数,重载“()”操作符
    bool operator() (const int &a, const int &b)
    {
        if(a != b)
            return a > b;
        else
            return a > b;
    }
};
int main()
{
    set<int, mycomp> s; //采用比较函数mycomp
    s.insert(5); //第一次插入5,可以插入
    s.insert(1);
    s.insert(6);
    s.insert(3);
    s.insert(5); //第二次插入5,重复元素,不会插入
    set<int,mycomp>::iterator it;
    for(it = s.begin(); it != s.end(); it++)
        cout << *it << " ";
    cout << endl;
    return 0;
}
/*
运行结果:6 5 3 1  
*/

九. 多重集合(multiset) 允许存在两个次序相等的元素的集合

与set用法一样,详细的,请上翻。
区别就是multiset 允许存在两个次序相等的元素的集合
申请:

multiset<int> a;

一个最近的实例,看T1改之后的

十. 列表(list) 由节点组成的双向链表,每个结点包含着一个元素

还没用到过,手写数组就好了

十一. sort

复杂度是 nlogn (log以2为底),类似于快排。 ※很常用的函数。
sort的功能很强大:
它可以对各种类型排序,只需要写一下自己的排序方式cmp就可以排各种序(vector,struct,string等),
1.需要提醒的是,对于字符串而言,sort默认的排序方式就是按照字典序。

#include<bits/stdc++.h> 
using namespace std;
int main()
{
    string s[10];
    cin>>s[1]>>s[2]>>s[3]>>s[4]>>s[5];
    sort(s+1,s+1+5);
    for(int i=1;i<=5;i++) cout<<s[i]<<" ";
}

结果:这里写图片描述
2.sort默认由小到大排序,但也可以用封装好的从大到小排序

less<数据类型>()//从小到大排序
greater<数据类型>()//从大到小排序

无需定义,在头文件algorithm中

 sort(a,a+10,greater<int>());  sort(a,a+10,greater<char>());
 sort(a.begin(),a.end());  //对于stl的容器来说

3.对结构体等排序的cmp写法

struct node{int x,y;}e[maxn];
bool cmp(node a,node b){return a.x>b.x}//node为结构体类型,按照x的降序排序
sort(e+1,e+1+n,cmp);

十二. memeset

memset实际上是用来对一段内存空间全部设置为某个字符,但是对于0,-1的值是可以直接赋的(至于为什么,蒟蒻也不知道)。
对于它的复杂度,据说如果不是赋值字符的话,也是O(n)的,不过常数很小,相对于for循环来说好用很多。
这里有一段测试代码

#include<iostream>
#include<cstring>//memset的头文件
using namespace std;
int a[20],b[20],c[20],d[20],e[20],f[20],g[20];
char ch[20];
int main()
{
    memset(a,0,sizeof(a));
    memset(b,-1,sizeof(b));
    memset(c,1,sizeof(c));
    memset(d,127,sizeof(d));
    memset(e,127/3,sizeof(e));
    memset(f,0x3f3f3f3f,sizeof(f));
    memset(g,0x7f7f7f7f,sizeof(g));
    memset(ch,'z',sizeof(ch));
    for(int i=1;i<=5;i++)   cout<<a[i]<<" "; cout<<endl;
    for(int i=1;i<=5;i++)   cout<<b[i]<<" "; cout<<endl;
    for(int i=1;i<=5;i++)   cout<<c[i]<<" "; cout<<endl;
    for(int i=1;i<=5;i++)   cout<<d[i]<<" "; cout<<endl;
    for(int i=1;i<=5;i++)   cout<<e[i]<<" "; cout<<endl;
    for(int i=1;i<=5;i++)   cout<<f[i]<<" "; cout<<endl;
    for(int i=1;i<=5;i++)   cout<<g[i]<<" "; cout<<endl;
    for(int i=1;i<=5;i++)   cout<<ch[i]<<" "; cout<<endl;
}

运行结果:
运行结果
可以看到,memset赋字符好很用,(string好像不行)。
直接赋1的话,其结果已经到了10^7的级别,在int内最大得赋值控制在0x7f7f7f7f就好。而对于spfa等算法int内的最大值inf最佳的赋值是0x3f3f3f3f(和int范围一个级别,但两两相加不爆int),(127/3也可以,稍小一点),因为在松弛的时候如果memset赋的最大值是0x7f7f7f7f,即2319062143稍加上一个数就会爆int。int的最大值2^31-1=2147483647.
对于结构体的清零操作:

struct tre{ int li,ri;}deep[32];
int main()
{
    deep[5].ri=99;
    memset(&deep,-1,sizeof(deep));//0也可以 
    cout<<deep[5].ri;
}

十三. swap

swap是一个很强大的交换函数,可以交换各种类型(string,vector等,后者很麻烦,不举例)。

十四. lower_bound,upper_bound,binary_search

比较实用又比较玄学,lower_bound和upper_bound的复杂的是二分的复杂度,即logn(以2为底)。
一些容器(set,vector等)也支持lower_bound等操作。

首先要进行sort排序。


lower_bound 用于在一个升序序列中查找某个元素,并返回第一个不小于该元素的元素的迭代器,如果找不到,则返回指向序列中最后一个元素之后的迭代器。通过 -a(a是变量名)的方式获取排名。


upper_bound 用于在一个升序序列中查找某个元素,并返回第一个大于该元素的元素的迭代器,如果找不到,则返回指向序列中最后一个元素之后的迭代器。通过 -a的方式获取排名。


binary_search 用于确定某个元素有没有在一个升序序列中出现过,返回 true 或 false。
三者的例子:

#include <cstdio>
#include <algorithm>
#include<iostream>
using namespace std;
int n;
int a[10]={-5,1,3,-2,5,6,8,9,4,-10};
int main() {
    sort(a,a+10);//-10,-5,-2,1,3,4,5,6,8,9
    int *it1=lower_bound(a,a+10,1); cout<<*it1<<endl;//第一个大于等于1的 输出 1
    int *it2=lower_bound(a,a+10,2); cout<<*it2<<endl;//输出 3
    int *it3=upper_bound(a,a+10,1); cout<<*it3<<endl;//第一个大于1的 输出 3
    int *it4=upper_bound(a,a+10,2); cout<<*it4<<endl;//输出 3
    bool b=binary_search(a,a+10,7); cout<<b<<endl;//数组中没有7 输出0 

    int pos=lower_bound(a,a+10,3)-a; cout<<pos;//输出3的位置 4 (0 1 2 3 4),即第五个 
}

容器中 用 container< T> :: iterator it;(其中 container 是容器类型,可以是 vector、set 等,T 是容器中元素的类型。)的方式申请迭代器,
it是container< T> :: iterator类型的数,可以与s.begin() s.end()作比较等操作。(其中s是容器类型的名称,如multiset < int> s;)。
*it指针返回查询的值。这里的it,只支持 it++ 和it - -的操作,不能it+i;
输出时,cout<<*it; 输出指向的值。
对于容器的操作,看之前做的题,T1优化后的


十五. unique

需要先排序,然后用unique进行去重操作,通过-a(a是变量名)获取数量位置
下面的代码演示了读入 n个数,并升序排序并去重后输出。

#include<iostream>  
#include<vector>  
#include<algorithm>  //unique头文件 
using namespace std;  
vector<int>a;  
int main()  
{  
    for(int i=1;i<10;i++)  
        for(int j=0;j<3;j++)  
            a.push_back(i);  

    sort(a.begin(),a.end());      
    a.erase(unique(a.begin(),a.end()),a.end());

    for(int i=0;i<a.size();i++)
        cout<<a[i]; 
    return 0;  
}  
/*也可以这样:
int count=unique(a,a+n)-a;
    for (int i=0; i<count;i++)
        printf("%d\n", a[i]);
        */

十六. min,max

较大值较小值,很简单也很常用

int a=1,b=99;
c=min(a,b);//c=1
d=max(a,b);//d=99
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值