day1 c++STL详解(代码举例+使用模板)

前言

因为前面已经在专栏写过基本的入门知识,这里就不再赘述了,主要是c和c++的基础知识,基本的输入输出,最基本的递归算法等,因此我从c++的STL入手。

STL是C++中的标准库,主要是模板和函数模板,使用这些函数可以省很多事。

STL简介

C++中的STL分为三类,算法(algorithm),容器(container),迭代器(iterator),一共十三个头文件:

<algorithm>
<deque>
<functional>
<iterator>
<vector>
<list>
<map>
<memory>
<numeric>
<queue>
<string>
<set>
<stack>
<utility>

其中,算法部分主要由头文件<algorithm>,<numeric>和<functional>组成。

容器包括<vector>,<list>,<deque>,<string>,<set>,<map>,<stack>和<queue>。

迭代器有<utility>,<iterator>和<memory>。

下面详解这些头文件和使用方法。

vector常见用法及其详解

1.vector的定义

vecto可以翻译为向量,我们可以理解为可变长度的数组。

如果遇到普通的数组超内存的情况,使用vector会让问题的解决便捷很多,而且也常常用于以邻接表存储图(日后补充)

在使用时,需要在头文件下加上

#include<vector>
using namespace std;

在定义时使用

vector<typename> name;

进行定义,typename可以自己定义,int,double,char…

2.访问vector内元素

访问可以有两种写法:

1.通过下标访问

这里无需赘述,跟普通的数组一样,例如vector数组vi可以通过vi[0]、vi[1]访问,但是注意这里的下标范围是0到vi.size-1

2.利用迭代器访问

迭代器|(iterator)类似于指针,定义方法为:

vector <typename> :: iterator it;

得到迭代器it后可以用*it可以访问vector里的元素。

vector<int> vi;
for(int i=1;i<=5;i++)
{
	vi.push_back(i);//push_back向vector末尾添加一个元素i;删除时用pop_back()删除尾元素。
}
//用it指向vi的首元素地址
vector<int>::iterator it = vi.begin();

for(int i=0;i<5;i++)
{
	cout<<*(it+i)<<endl;
}

另外,这里还要提一下跟begin()类似的end(),end()不同于begin取首元素,end()取的是尾元素的下一个地址,不存储任何元素,也就是常见的左闭右开思维。

//注意vector的迭代器不支持it<vi.end()的写法,因此我们写循环时写it!=vi.end();
for(vector<int>::iterator it=vi.begin();it!=vi.end();it++)
{
	cout<<*(it)<<endl;
}

3.补充自带函数:

自带函数size(),通过size()可以获得vector的元素个数,时间复杂度为O(1)。

自带函数clear(),通过clear()来清空vector元素,时间复杂度O(N)。

自带函数insert函数用来向vector内插入元素,使用方法是insert(it,x)在迭代器it位置插入一个元素x,复杂度为O(N)。

自带函数erase(),有两种用法删除单个元素或者某区间内所有元素。

  • erase(it)删除it处的元素
  • erase(first,last)删除从first到last的所有元素,包括first但不包括last。

2.set的常见用法详解

1.set定义

set翻译为集合,是一个内部自动有序且不含重复元素的容器。考试中常有需要去掉重复元素的情况,而且有可能因为某些元素较大或者不是int型而不能直接开散列表,这种情况下就可以用set来保留元素本身而不考虑它的个数,而且加入后会自动排序。

补充:存在一个名为multiset的集合,允许重复元素。

写法跟vector类似

#include<set>
using namespace std;

//定义方法
set<typename> name;

2.访问set内元素

不同于vector,set只能通过iterator访问。

#include <iostream>
#include <set>
 
using namespace std;
 
int main(){
     set<int> s;
     s.insert(1);
     s.insert(2);
     s.insert(3);
     s.insert(1);
     cout<<"set 的 size 值为 :"<<s.size()<<endl;
     cout<<"set 的 maxsize的值为 :"<<s.max_size()<<endl;
     cout<<"set 中的第一个元素是 :"<<*s.begin()<<endl;
     cout<<"set 中的最后一个元素是:"<<*s.end()<<endl;
     s.clear();
     if(s.empty())
     {
         cout<<"set 为空 !!!"<<endl;
     }
     cout<<"set 的 size 值为 :"<<s.size()<<endl;
     cout<<"set 的 maxsize的值为 :"<<s.max_size()<<endl;
     for(set<int>::iterator it=s.begin();it!=st.end();it++)
     {
     cout<<*(it)<<endl;
     //注意除了vector和string之外的容器都不支持*(it+i)的访问方式
     }
     return 0;
}

3.set常用自带函数

  1. insert(x)可以把x插入到set容器,自动递增排序,复杂度log(N)
  2. find(value)返回set中对应值为value的迭代器,复杂度也为log(N)
  3. erase()用法同vector
  4. size()返回set内元素个数
  5. clear()用于清空set中所有元素

3.string的常见用法详解

1.string的定义

定义如下;

#include<string>
using namespace std;
string str="abcdefg";

2.string中内容的访问

1.可直接像字符数组那样去访问string,输入和输出也可以用cin和cout,不再赘述。

如果想要用printf来输出string,可以用c_str()将string类型转换为字符数组输出。

#include<stdio.h>
#include<string>
using namespace std;
int main()
{
	string str="abcde";
	printf("%s\n",str.c_str());
	return 0;
}

2.利用迭代器访问

定义如下

string :: iterator it;

string就可以直接用迭代器加减某个数字进行访问例如,str.begin()+2

3.常用自带的函数

  1. operator+=:这是string的加法,将两个string拼接起来。可以直接用加法如string str1=“abcde”;string str2=“fgh”;string str3=str1+str2;
  2. length()/size():返回string的长度
  3. insert():有多种写法,如insert(pos,string)在pos位置插入字符串string,insert(it,it2,it3)it为原字符串欲插入位置,it2和it3位待查字符串的收尾迭代器,将串[it2,it3)插入到it位置
  4. erase():删除单个元素/删除某个区间内的元素
  5. clear():用于情况string的数据
  6. substr(pos,len):返回从pos号位置开始,长度为len的子串
  7. string::npos是一个常数值为-1,但由于unsigned_int类型,可以认为是该类型的最大值,。用于作为find函数失配时的返回值,可认为是-1或者4294967295
  8. find():str.find(str2)当str2是子串时,返回其位置,否则返回string::npos;str.find(str2,pos)从str的pos号位置开始匹配str2,返回值与上面相同
  9. replace(pos,len,str2)把str从pos号位置开始,长度为len的子串替换为str2,replace(it1,it2,str2)把str的迭代器[it1,it2)范围的子串替换为str2。

4.map的常见用法详解

1.map的定义

map翻译为映射,map可以将任何基本类型(包括STL容器)映射到任何基本类型的容器(包括STL容器),例如string到int的映射等。这就类似于字典,给出某个键,就必然有某个值跟它对应。

使用方法:

#include<map>
using namespace std;
map<typename1,typename2> mp;

前一个类型是键,后一个类型是值。注意:如果要建立字符串到整型的映射,必须用string而不能用char的数组。

常用于:

  1. 建立字符(字符串)与整数之间的映射
  2. 判断大整数或者其他类型的数据是否存在,可以把map当做bool数组使用
  3. 字符串和字符串之间的映射

2.map容器内元素的访问

1.通过下标访问
例如,对于map<char,int>mp来说,可以直接用mp[‘c’]来访问c对应的整数。当然map键是唯一的。

2.利用迭代器访问
定义如下:

map<typename1,typename2>::iterator it;

map的迭代器it可以用it->first和it->second来访问值

3.map实用函数实例解析

  1. find(key),返回键位key的迭代器,复杂度为O(logN)
  2. erase()两种用法,删除单个元素或者某个区间内的元素,erase(it)删除it所指向的元素的迭代器,erase(key)key使用想要删除的映射的键,erase(first,last)删除[first,last)的元素。
  3. size()获得map元素的个数
  4. clear()情况map中的所有元素

5.queue的常见用法详解

1.queue定义

queue是队列,是一个先进先出的容器。

使用方法:

#include<queue>
using namespace std;
queue<typename> name;

用途:
用于实现广度优先搜索
注意:使用front和pop函数前使用empty判断队列是否为空

2.queue容器内元素的访问

因为队列是先进先出的,因此在STL中只能通过front()来访问队首元素,或者back()来访问队尾元素。

3.queue常用函数实例解析

  1. push(x)将x加入队首
  2. front()、back()返回队首和队尾元素
  3. pop()令队列最前面的元素出队
  4. empty()检查queue是否为空
  5. size()返回元素个数

6.priority_queue的常见用法详解

1.priority_queue的定义

priority_queue又叫做优先队列,是利用堆来实现的,队首元素永远是优先级最好的哪一个。是对普通队列的延伸。

定义:

#include<queue>
using namespace std;
priority_queue<typename>name;

用途
解决某些贪心问题,也可以对Dijkstra算法进行优化。

2.priority_queue元素的访问

优先队列不同于普通队列,只能通过top()访问队首元素

3.priority_queue常用函数

  1. push(x),令x入队
  2. top(),访问队首元素
  3. pop(),将队首元素删除
  4. empty(),判断队列是否为空
  5. size(),返回队列元素个数

4.priority_queue元素优先级设置

1.基本数据类型的优先级设置

基本数据类型为int,double,char等类型,优先队列一般对它们的优先级设置是数字达到优先级越高,因此队列的首元素一般是最大的那个,如果是char类型那么是字典序最大的。

priority_queue<int>q;//这是按照最大的元素在队首设置的
//如果想要让优先队列把最小的元素放在队首,需要进行如下定义
priority_queue<int,vectot<int>, greater<int>> q;

2.结构体的优先级设置

例如如下结构体:

struct fruit
{
	string name;
	int price;
};
//如果想要按照水果价格优先级高,那就需要重载小于号
//“<”,也就是改变小于号的定义
struct fruit
{
	string name;
	int price;
	friend bool operator <(fruit f1,fruit f2)
	{
		return f1.price<f2.price;
	}
}

7.stack的常见用法详解

1.stack定义

stack是栈,是一个先进后出的容器。
定义:

#include<stack>
using namesapce std;
stack<typename> name;

用法:
用来模拟实现某些递归,防止程序对栈内存的限制而导致程序出错,一般来说,程序的栈内存空间小,对于很多要求来说会导致溢出。

2.stack容器内元素的访问

stack是一种后进先出的容器,因此可以通过top()来访问栈顶元素。

3.stack常用函数解析

  1. push(x),将x入栈
  2. top()获得栈顶元素
  3. pop()删除栈顶元素
  4. empty()检测stack内容是否为空
  5. size()返回元素个数

8.pair常见用法详解

1.pair定义

pair可以将两个元素绑定在一起合成一个元素,可以等价为一个结构体。

定义方法:

#include<utility>
using namespace std;
//如果记不住头文件可以直接用map代替,map头文件中包含了pair的定义
pair<typename1,typename2> name;
//例如pair<string,int>p;
//定义pair初始化时可以用小括号例如:
//pair<string,int>p("abcde",5);
//也可以用p=make_pair("abcde",5);

常见用法:
1.代替二元结构体,节省代码
2.可以作为map的键值对进行插入,例如

map<string,int> mp;
mp.insert(make_pair("abce",5));

2.pair中元素的访问

pair中有两个元素,分别为first和second,按照正常的结构体访问就可以。

3.pair常用函数实例解析

1.比较操作数:pair可以直接用==,!=,<,>比较,规则是先比较first,再比较second。

9.algorithm下的常用函数

algorithm中包括了很多实用数学函数,例如求最大,最小等等

  1. max(x,y),min(x,y),abs(x)分别是返回xy中的最大值,最小值,x的绝对值
  2. swap(x,y)交换x,y的值
  3. reverse(it,it2)可以将在[it,it2)之间的元素进行反转
  4. next_permutation()给出一个序列在全排列中的下一个序列,这可能读起来有些麻烦。
    例如n==3时,全排列为:
123
132
213
231
312
321
这样123的下一个序列就是132

可以用以下代码获得全排列:

#include<stdio.h>
#include<algorithm>
using namespace std;
int main()
{
	int a[10]={1,2,3}
	//a[0]~a[2]之间的徐磊需要求解next_permutation
	do{
	printf("%d%d%d\n",a[0],a[1],a[2]);
	}while(next_permutation(a,a+3));
}
  1. fill(),把数组或者容器中某个区间赋值为某个相同的值。和memset不同,这里的复制可以是数组类型对应范围中人一直。
  2. sort(),用来排序的函数,类似于c语言的qsort但是qsort很繁琐,比起来,sort更好用。
sort(首元素地址,尾元素地址的下一个地址,比较函数)

例如对某个数组a[6]={9,4,2,1,5,7},可以用sort(a,a+6)进行从小到大排序,如果想改变比较方法cmp。

bool cmp(int a,int b)
{
	return a>b;
	//可以理解为当a>b时把a放在b前面
}
//比较时
sort(a,a+6,cmp);

此外对结构体也可以排序

struct node
{
	int x,y;
}s[10];
bool cmp(node a, node b)
{
	return a.x>b.x;
}
//对s[10]赋值后
sort(s,s+10,cmp);
//可以对结构体s进行排序

也可以对容器进行排序,例如vector,string,deque等,注意数据类型,首位地址即可。

  1. lower_bound(),upper_bound(),lower_bound(first,last,val)和upper_bound(first,last,val)分别用于寻找在数组或者容器中[first,last)第一个值大于等于或者大于val的元素,如果是数组则返回指针,容器返回迭代器
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值