C++常用STL讲解

关于STL(标准模板库)

Standard Template Library,缩写:STL
STL是一个C++软件库,里面包含算法(algorithms)、容器(containers)、函数(functions)、迭代器(iterators)

C语言版本

#include<stdio.h>
int main(){
    int a,b;
    scanf("%d%d",&a,&b);
    printf("%d",a+b);
    return 0;
}

C++版本

#include<bits/stdc++.h>
using namespace std;
int main(){
    int a,b;
    cin>>a>>b;
    cout<<a+b;
    return 0;
}

C++也可以兼容C语言

#include<bits/stdc++.h>
using namespace std;
int main(){
    int a,b;
    scanf("%d%d",&a,&b);
    printf("%d",a+b);
    return 0;
}

C++中的引用

#include<bits/stdc++.h>
using namespace std;

void swap2(int &a,int &b){
    int c=a;
	a=b;
	b=c;
}

int main(){
	int a,b;
	cin>>a>>b;
	swap2(a,b);//交换两个数的值
	cout<<a<<""<<b;
    return 0;
}

引用是C++新增的内容,就同C语言的指针一样重要,但它的指针更加方和易用,有时候甚至是不可或缺的。同指针一样,引用能够减少数据的拷贝,提高数据的传递效率。

字符串(String)
String是STL中的一个重要的部分,主要用于字符串处理。可以使用输入输出流方式直接进行String读入输出,类似于C语言中的字符数组,由C++的算法库对String类也有着很好的支持,大多时候字符串处理的问题使用String要比字符数组更加方便。

博客推荐:https://www.cnblogs.com/nanyangzp/p/3607534.html

字符串(String)

创建String类型变量

  • String s;直接创建一个空的(大小为0)的String类型变量s
  • String s = *char;创建String时直接用字符串内容对其赋值,注意字符串要用双引号“”
  • String s(int n,char c);创建一个String,由n个c组成,注意c是字符型要用单括号‘ ’

读入String

  • cin>>s;读入s,遇到空格或回车停止,无论原先s是什么内容都会被新读入的数据替代
  • getline(cin,s);读入s,空格也同样会读入,直到回车才会停止

输出String

  • cout<<s;将s全部输出到一行(不带回车)

赋值、比较、连接运算符:
赋值运算符:=将后面的字符串赋值给前面的字符串O(n)

比较运算符:== != < <= > >=比较的是两个字符串的字典序大小O(n)

连接运算符:+ +=将一个运算符加到另一个运算符后面O(n)

  • s[index]返回字符串s中下标为index的字符,String中下标也是从0开始O(1)

  • s.substr(p,n)返回从s的下标p开始的n个字符组成的字符串,如果n省略就取到底O(n)

  • s.length()返回字符串的长度O(1)

  • s.empty()判断s是否为空,空返回1,不空返回0,O(1)

  • s.erase(p0,len)删除s中从p0开始的len个字符,如果len省略就删到底O(n)

  • s.erase(s.begin()+i)删除下标为i个字符O(n)

  • s1.insert(p0,s2,pos,len)后两个参数截取s2,可以省略O(n)

  • s.insert(p0,n,c)在p0处插入n个字符c O(n)

  • s1.replace(p0,len0,s2,pos,len)删除p0开始的len0个字符,然后在p0处插入串s2中从pos开始的len个字符,后两个参数可以省略O(n)

  • s1.find(s2,pos)从前往后,查找成功时返回第一次出现的下标,失败返回string::npos的值(-1)O(n*m)

  • s1.rfind(s2,pos)从pos开始从后向前查找字符串s2中字符串在当前串后边第一次出现的下标O(n*m)

动态数组(vector)

vector容器是STL中最常用的容器之一,它和array容器非常类似,都可以看做是对C++普通数组的“升级版”。不同之处在于,array实现的是静态数组(容量固定的数组),而vector实现的是一个动态数组,即可以进行元素的插入和删除,在此过程中,vector会动态调整所占用的内存空间,整个过程无需人工干预。

博客推荐:http://blog.csdn.net/w_linux/article/details/71600574

  • vector<type> v创建动态数组v,后面可以加{}或()进行初始化
  • type v[index]获取v中第index个元素O(1)
  • v.push_back(type item)向v后面添加一个元素item O(1)
  • v.pop_back()删除v最后一个元素O(1)
  • v.size()获取v中元素个数,返回size_type类型O(1)
  • v.resize(int n)把v的长度设定为n个元素O(n)
  • v.empty()判断v是否为空,空返回1,不空返回0,O(1)
  • v.clear()清空v中的元素O(size)
  • v.insert(iterator it,type x)向迭代器it指向元素前增加一个元素x,O(n)
  • v.erase(iterator it)删除向量中迭代器指向元素,O(n)
  • v.front()返回首元素的引用O(1)
  • v.back()返回尾元素的引用O(1)
  • v.begin()返回首迭代器,指向第一个元素O(1)
  • v.end()返回尾迭代器,指向向量最后一个元素的下一个位置O(1)

vector创建代码样例:

//vector的创建
#include<bits/stdc++.h>
using namespace std;
int main(){
    vector<int> v1;
    //创建一个存int类型的动态数组,int可以改成其他类型
    vector<double> v2{1,1,2,3,5,8};
    //创建一个存double类型的动态数组,长度为6,1 1 2 3 5 8分别存在v[0]-v[5]
    vector<long long> v3(20);
    //创建一个存long long类型的动态数组,长度为20,v[0]-v[19]默认为0
    vector<String> v4(20,"zzuacm");
    //创建一个存String类型的动态数组,长度为20,存的都是"zzuacm"
    vector<int> v5[3];
    //相当于存int的二维数组,一共3行,每行的列可变
    vector<vector<int>> v5{{1,2},{1},{1,2,3}};
    //存int的二维数组,行和列都可变,初始状态
    return 0;
}
int main(){
	vector int v;
	for(int i=1;i<=5;i++)
		v.push_back(i);//向动态数组中插入1~5
	cout<<v.size()endl;//输出数组的大小,有几个值
	for(int i=0;i<5;i++)
		cout<<v[i]<<" ";//输山v[0]~v[4],也就是1~5
	cout<<endl;
	v.clear();//将v清空,此时size为0
	v.resize(10);//为v重新开辟大小为10的空间,初始为0
    for(int i=0;i<v.size();i++)
		cout<<v[i]<<" ";//遍历每一个元素
	while(!v.empty())//当v还不空的话,去掉v的最后一个元素,等同于v.clear()
        v.pop_back();
    return 0;
}
int main(){
	vector<int> v{0,1,2,3,4};
	v.erase(v.begin()+3);//删除v[3],v变为{0,1,2,4}
	v.insert(v.begin()+3,666);//在v[3]前加上666,v变成{0,1,2,666,4}
	v.front()=10;//将v[0]改成10,等同于v[0]=10;
	v.back()=20;//将v[4]改成20等同于v[v.size()-1]=20;
	for(int i=0;i<v.size();i++)
		cout<<v[i]<<" ";//使用下标访问的方法遍历v
	cout<<endl;
 	for(auto i=v.begin();i!=v.end();i++)
	cout<<i<<" ";//使用迭代器,从v.begin()到v.end()-1
	cout<<endl;
	for(auto i:v)//使用C++新特性循环遍历v,如果需要改变i的值,还需要在前面加上&
	cout<<i<<" ";
	cout<<endl;
	return 0;
}

关于迭代器(iterator)

vector<int>::iterator it=v.begin();等价于auto it=v.begin();

在这里it类似于一个指针,指向v的第一个元素
it等价于&v[0]
*it等价于v[0]
it也可以进行加减操作,例如it+3指向第四个元素
it++后it指向的就是v的第二个元素(v[1])了

队列(queue)
queue只能在容器的末尾添加新元素,只能从头部移除元素。

博客推荐:https://www.cnblogs.com/hdk1993/p/5809180.html

创建方法:
queue<type> q;建立一个存放数据类型为type的队列q

使用方法:

  • q.push(item):在q的最后添加一个type类型元素item O(1)
  • q.pop():使q最前面的元素出队O(1)
  • q.front():获取q最前面的元素O(1)
  • q.size():获取q中元素个数O(1)
  • q.empty():判断q是否为空,空返回1,不空返回0 O(1)

优先队列(priority_queue)
priority_queue中出队顺序与插入顺序无关,与数据优先级有关,本质是一个堆

博客推荐:https://blog.csdn.net/qq_41822647/article/details/88899915

创建方法:
priority_queue<Type, Container, Functional>
// Type:数据类型
// Container:存放数据的容器,默认用的是 vector
//Functional:元素之间的比较方法,当type可以比较时后两个可以省略

使用方法:

  • pq.push(item):在pq中添加一个元素 O(logn)
  • pq.top():获取pq最大的元素 O(1)
  • pq.pop():使pq中最大的元素出队 O(logn)
  • pq.size():获取pq中元素个数 O(1)
  • pq.empty():判断pq是否为空 O(1)

样例:

#include<bits/stdc++.h>
using namespace std;
int main(){
    priority_queue<int> pq;
    //priority_queue<int,vector<int>,greater<int>> pq;
    pq.push(1);
    pq.push(3);
    pq.push(2);
    while(!pq.empty()){
        cout<<pq.top()<<endl;
        pq.pop();
    }
    return 0;
}

Output:

3

2

1

#include <bits/stdc++.h>
using namespace std;
struct Node{
	int x,y;
};
bool operator<(Node a,Node b){
	return  a.x<b.x;
}
int main(){
	priority_queue<Node> pq;
	pq.push({1,3});
	pq.push({3,2});
	pq.push({2,1});
 	while(!pq.empty()){
        cout<<pq.top().x<<' '<<pq.top().y<<endl;
        pq.pop();
    }
    return 0;
}

Output:

3 2

2 1

1 3

priority_queue中存的元素如果是结构体这样无法进行比较的类型,必须要重载运算符<,相当于先使得优先队列中的元素可以进行比较再建立pq,否则直接建优先队列是会报错的

集合(set)
集合(set)是一种包含对象的容器,可以快速地(logn)查询元素是否在已知几集合中。
set中所有元素是有序地,且只能出现一次,因为set中元素是有序的,所以存储的元素必须已经定义过[<]运算符(因此如果想在set中存放struct的话必须手动重载[<]运算符,和优先队列一样)
与set类似的还有:

  1. multiset元素有序可以出现多次
  2. unordered_set元素无序只能出现一次
  3. unordered_multiset元素无序可以出现多次

博客推荐:https://www.cnblogs.com/zyxStar/p/4542835.html

集合(set)
建立方法:
*set<Type> s;
multiset<Type> s;
unorded_set<Type> s;
unorded_multiset<Type> s;
如果Type无法进行比较,还需要和优先队列一样定义<运算符

遍历方法:
for (auto i:s)cout<< i <<" ";
//和vector的类似

使用方法:

  1. s.insert(item):在s中插入一个元素 O(logn)

  2. s.size():获取s中元素个数 O(1)

  3. s.empty():判断s是否为空 O(1)

  4. s.clear():清空s O(n)

  5. s.find(item):在s中查找一个元素并返回其迭代器,找不到的话返回s.end() O(logn)

  6. s.begin():返回s中最小元素的迭代器,注意set中的迭代器和vector中的迭代器不同,无法直接加上某个数,因此要经常用到–和++ O(1)

  7. s.end():返回s中最大元素的迭代器的后一个迭代器 O(1)

  8. s.count(item):返回s中item的数量。在set中因为所有元素只能在s中出现一次,所以返回值只能是0 或1,在multiset中会返回存的个数 O(logn)

  9. s.erase(position):删除s中迭代器position对应位置的元素 O(logn)

  10. s.erase(item):删除s中对应元素 O(logn)

  11. s.erase(pos1,pos2):删除[pos1,pos2]这个区间的位置的元素 O(logn+pos2-pos1)

  12. s.lower_bound(item):返回s中第一个大于等于item的元素的迭代器,找不到就返回s.end() O(logn)

  13. s.upper_bound(item):返回 s中第一个大于item的元素的迭代器,找不到就返回s.end() O(logn)

映射(map)
map是照特定顺序存储由key和value的组合形成的元素的容器,map中元素按照key进行排序,每个key都是唯一的,并对应着一个value,value可以重复。
map的底层实现原理与set一样都是红黑树。
与map类似的还有unordered_map,区别在于key不是按照顺序排序

博客推荐:https://www.cnblogs.com/panweiwei/p/6657583.html

建立方法:

map<key,value> mp;

unordered_map<key,value> mp;

遍历方法:

for(auto i:mp)

​ cout<<i.first<<’ '<<i.second<<endl;

map的常用函数:

  1. mp.size():获取mp中元素个数 O(1)

  2. mp.empty():判断mp是否为空 O(1)

  3. mp.clear():清空mp O(1)

  4. mp.begin():返回mp中最小key的迭代器,和set一样,只可以用到–和++操作 O(1)

  5. mp.end():返回mp中最大key 的迭代器的后一个迭代器 O(1)

  6. mp.find(key):在mp中查找一个key 并返回其iterator,找不到的话返回s.end() O(logn)

  7. mp.count(key):在mp中找key的数量,因为map中key唯一,所以只会返回0或1 O(logn)

  8. mp.erase(key):在 mp 中删除key 所在的项,key和value都会被删除 O(logn)

  9. mp.lower_bound(item):返回mp中第一个key大于等于item的迭代器,找不到就返回mp.end()0(logn)

  10. mp.upper_bound(item):返回 mp中第一个key大于item的迭代器,找不到就返回mp.end() O(logn)

  11. mp[key]:返回 mp中 key 对应的 value。如果key 不存在,则返回 value 类型的默认构造器(defaultconstructor)所构造的值,并该键值对插入到mp中 O(logn)

  12. mp[key] = xxx:如果mp中找不到对应的key则将键值对(key:xxx)插入到mp中,如果存在key则将这个key对应的值改变为xxx O(logn)

unordered的作用:
set和map都可以在前面加上unorder_使得内部的元素改成不按顺序存储的,其余的功能都不改变,虽然无法顺序存储,但底层原理是hash,可以使得所有的查询、修改、删除操作都变成O(1)复杂度

二进制有序集(bitset)
bitset是一种类似数组的结构,它的每一个元素只能是0或1,每个元素仅用1bit空间。

博客推荐:https://blog.csdn.net/qq_52023825/article/details/122409539

建立方法:

  1. bitset<n> b;//建立一个可以存n位二进制的有序集
  2. bitset<n> b(unsigned long u);//坐标从后往前计数,高位在前
  3. bitset<n> b(String s);//将由‘0’和‘1’组成的字符串赋值给支持所有位操作:| |= & &= << <<= >> >>=
  4. cout<< b;//bitset可以直接用cout输出b[index];//可以用下标操作符来读或写某个索引位置的二进制位
    //比如bitset<10>b(5);等价于bitset<10>b(“1010”);
    //其中cout<<b输出0000001010
    //for(int i=0;i<10;i++)cout<<b[i];输出0101000000

使用方法:

  1. b.count();//count函数用来求bitset中1的位数

  2. b.size();//size函数用求求bitset的大小

  3. b.any();//any函数检否bitset中是否有1

  4. b.none();//none函数检查bitset中是否没有1

  5. b.all();//all函数检查bitset中是全部为1

  6. foo.flip();//flip函数不指定参数时,将bitset每一位全部取反

  7. foo.set();//set函数不指定参数时,将bitset的每一位全部置为1

  8. foo.reset();//reset函数不传参数时将bitset的每一位全部置为0

  9. String s = foo.to_string();//将bitset转换成String类型

  10. unsigned long a=foo.to_ulong();//将bitset转换成unsigned long类型

  11. unsigned long long b=foo.to_ullong();//将bitset转换成unsigned long long类型

常用函数:

  • max(val1,val2):返回更大的数
  • min(val1,val2):返回更小的数
  • swap(type,type):交换两者的值,可以是两个值也可以是两个STL的容器

排序函数(sort)

sort(first, last, compare)

  • first:排序起始位置(指针或 iterator)
  • 1ast:排序终止位置(指针或iterator)
  • compare:比较方式,可以省略,省略时默认按升序排序,如果排序的元素没有定义比较运算(如结构体),必须有compare

sort排序的范围是[first,last],时间为 O(nlogn)

sort基本样例:

#include<bits/stdc++.h>
using namespace std;
bool cmp(int a,int b){
	return a>b;
}
int main(){
	int arr[]={3,2,5,1,4};
	sort(arr,arr+5);
	sort(arr,arr+5,greater<int>());
	sort(arr,arr+5,cmp);
	sort(arr,arr+5,[](int a,int b){returm a>b;});
    return 0;
}

去重函数(unique)
unique(first, last):

  • [first,last]范围内的值必须是一开始就提前排好序的
  • 移除[first,last]内连续重复项
  • 去重之后的返回最后一个元素的下一个地址(迭代器)
#include<bits/stdc++.h>
using namespace std;
int main(){
	int arr[]{3,2,2,1,2},n;
	sort(arr,arr+5)//需要先排序
	n=unique(arr,arr+5)-arr;//n是去重后的元素个数
	return 0;
}

二分函数(lower_bound/upper_bound)

​ lower_bound(first,last,value)

  • first:查找起始位置(指针或 iterator)

  • last:查找终止位置(指针或iterator)

  • value:查找的值

  • lower_bound 查找的范围是[first,last],返回的是序列中第一个大于等于value的元素的位置,时间为 O(logn)

  • [first,last]范围内的序列必须是提前排好序的,不然会错

  • 如果序列内所有元素都比value小,则返回last

upper_bound(first, last, value)

  • upper_bound与 lower_bound相似,唯一不同的地方在于upper_bound查找的是序列中第一个大于value的元素

二分函数样例:

int main(){
    int arr[]={3,2,5,1,4};
    sort(arr,arr+5);//需要先排序
    cout<< *lower_bound(arr,arr+5,3);//输出数组中第一个大于等于3的值
    return 0;
}

next_permutation
next_permutation(first,last)
用于求序列[first,last]元素全排列中一个排序的下一个排序

#include<bits/stdc++.h>
using namespace std;
int main(){
	int a[3] {0,1,2};
    do{
    	for(int i=0;i<3;i++)
			cout<<a[i]<<' ';
		cout<<endl;
    }
	while(next_permutation(a,a+3));
	return 0;
}
  • 12
    点赞
  • 104
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值