首页 > 其他分享 >stl标准库

stl标准库

时间:2023-11-27 15:11:17浏览次数:36  
标签:容器 end 迭代 iterator stl 元素 param 标准

STL标准库

1. STL概念

为了建立数据结构和算法的一套标准,并且降低他们之间的耦合关系,以提升各自的独立性、弹性、交互操作性(相互合作性,interoperability),诞生了STL

​ STL(Standard Template Library,标准模板库),是惠普实验室开发的一系列软件的统称。现在主要出现在 c++中,但是在引入 c++之前该技术已经存在很长时间了。

​ STL(Standard Template Library)标准模板库,在我们 c++标准程序库中隶属于 STL 的占到了 80%以上。

六大组件:

容器:数据结构,用于存放数据【类模板】
算法:操作数据的各种功能,如删除、排序、查询等【函数模板】
迭代器:算法借助迭代器操作数据(主要读数据) 【各种运算符重载】
仿函数:算法的某种策略,增强算法的功能。【()运算符重载】
适配器:用于扩展容器、算法、迭代器的接口
空间管理器:负责空间的配置与管理 【类模板】

​ STL优点:

1)STL是C++的一部分,不需要安装外部库
2)STL将数据和操作分离
3)STL具有高可重用性,高性能,高移植性,跨平台的优点
   高可重用性:采用了模板类和模板函数
   高性能:可以高效地从大量的数据中快速查找,如map采用红黑树的结构
   高移植性:只要存在C++的编译环境的操作系统,都可以编译和运行STL模块。

STL 之父 Alex Stepanov 亚历山大·斯特潘诺夫(STL 创建者)。

2. STL三大组件的基本用法

容器(数据结构,vector,set,map,queue等)、算法(插入数据、删除数据、修改数据、排序等)、迭代器(算法操作容器)

2.1 容器

容器:用于存放数据

常用的数据结构

数组(array) 链表(list) 树(tree) 栈(stack) 队列(queue) 集合(set) 映射表(map)

根据数据在容器中的排列特性:序列式容器、关联式容器

序列式容器:
     强调值的排序,每个元素均有固定的位置,除非用删除或插入的操作改变这个位置。如:vector,deque/queue,list;
关联式容器:
     非线性,更准确的说是二叉树结构,各元素之间没有严格的物理上的顺序关系;在数据中选择一个关键字key,这个key对数据起到索引的作用,方便查找。如:set/multiset,map/multimap容器

【注】容器可以嵌套容器

2.2 算法

算法(Algorithm):用于解决问题

STL收录的算法经过了数学上的效能分析与证明,是极具复用价值的,包括常用的排序,查找等。特定的算法往往搭配特定的数据结构,算法与数据结构相辅相成。

算法分为:质变算法和非质变算法

质变算法:是指运算过程中会更改区间内的元素的内容。例如拷贝、替换、删除等
非质变算法:是指运算过程中不会更改区间内的元素内容。如查找、统计、求极值等。

2.3 迭代器

迭代器(iterator)是一种抽象的设计概念,使之能够依序寻访某个容器所含的各个元素,而又无需暴露该容器的内部表示方式

简之,迭代器是依次遍历容器中所有的元素

迭代器的种类:

输入迭代器:只读数据,支持++、==、!=
输出迭代器:只写数据,支持++
向前迭代器:读写数据(向前),支持++、==、!=
双向迭代器:读写数据(向前、向后),支持++、--
随机迭代器:提供读写操作(跳跃式访问任意位置),支持++、--、[]、-n、<、<=、>、>=

3. STL常见容器的应用

3.1 string 容器

string也是字符串的类型,可以理解它是用于存放字符的容器

3.1.1 string和c风格字符串对比

1)char*是一个指针,string是一个类
2)string封装了很多实用的成员方法
  查找find,拷贝copy,删除delete,替换replace,插入insert
3)不用考虑内存释放和越界
  string管理char*所分配的内存,每一次string的赋值,取值都由string类负责维护,不用担心赋值越界和取值越界等

3.1.2 string容器api

//构造函数
string(); //创建一个空的字符串 string str;
string(const string& str); //使用一个string对象初始化另一个string对象
string(const char* s); //使用字符串s初始化
string(int n,char c); //使用n个字符c初始化

//赋值
string& operator=(const char* s); //char*类型字符串 赋值给当前的字符串
string& operator=(const string &s); //把字符串s赋值给当前的字符串
string& operator=(char c); //字符赋值给当前的字符串
string& assign(const char*s);//把字符串s赋值给当前的字符串
string& assign(const char*s,int n);//把字符串s的前n哥字符赋给当前的字符串
string& assign(const string &s);//把字符串s赋给当前字符串
string& assign(int n,char c);//用n个字符c赋给当前字符串
string& assign(const string &s,int start,int n);//将s从start开始n个字符赋值给字符串

//取值
char& operator[](int n);//通过[]方式取字符
char& at(int n);//通过at方法取字符

//字符串拼接
string& operator+=(const string& str); //重载+=操作符
string& operator+=(const char* str); //重载+=操作符
string& operator+=(const char c);//重载+=操作符
string& append(const char*s);//把字符串s连接到当前字符串结尾
string& append(const char*s,int n);//把字符串s的前n个字符连接到当前字符串结尾
string& append(const string &s); //同operator+=()
string& append(const string &s,int pos,int n);//把字符串s从pos的n个字符连接到当前字符串结尾
string& append(int n,char c);//在当前字符串结尾添加n个字符c

//查找与替换
int find(const string& str,int pos=0)const;//查找str第一次出现位置,从pos开始查找,如果未查找到返回-1
int find(const char* s,int pos=0)const;//查找s第一次出现位置,从pos开始找
int find(const char* s,int pos,int n)const;//从pos位置查找s的前n个字符第一次位置
int find(const char c,int pos=0)const;//从pos位置查找c第一次出现位置
int rfind(const string& str,int pos=npos)const;//查找str最后一次位置,从pos开始查找
int rfind(const char* s,int pos=npos)const;//从pos开始查找s最后一次位置
int rfind(const char* s,int pos,int n)const;//从pos查找s的前n个字符最后一次位置
int rfind(const char c,int pos=0)const;//查找字符c最后一次出现位置
string& replace(int pos,int n,const string& str);//替换从pos开始n个字符为字符串str
string& replace(int pos,int n,const char* s);//替换从pos开始的n个字符为字符串s

//比较,返回值 0;相等,1;大于s,-1;小于s
int compare(const string &s)const;//与字符串s比较
int compare(const char *s)const;//与字符串s比较

//截取子字符串
string substr(int pos=0,int n=npos)const;//返回由pos开始的n个字符组成的字符串

//插入与删除
string& insert(int pos,const char* s);//插入字符串
string& insert(int pos,const string& str);//插入字符串
string& insert(int pos,int n,char c);//在指定位置插入n个字符c
string& erase(int pos,int n=npos);//删除从pos开始的n个

//转成char*
const char* c_str()  将当前字符串转成char*

//获取字符串的长度
int size();

3.2 vector容器

3.2.1 vector与数组的区别

vector的结构类同于数组,数组是静态的,在定义时确定的数组的大小;而vector是动态的,添加元素时如果空间不足时,则会自动扩容器(2^n);整体来说,vector比较灵活的,而且vector是类模板,可以存放任意类型的元素

image-20231124111701011

3.2.2 vector迭代器

vector维护一个线性空间(线性连续空间),vector迭代器所需要的操作行为是(*,->,++,--,+,-,+=,-=)运算符重载等。vector支持随机存取,vector提供的是随机访问迭代器(Random Access Iterator),迭代器中的元素即为vector容器中的元素。

【注】vector扩容之后,原迭代器则无效,需要重新获取迭代器

所谓动态增加大小,并不是在原空间之后续接新空间(因为无法保证原空间之后尚有可配置的空间),而是一块更大的内存空间,然后将原数据拷贝新空间,并释放空间。
因此,对vector的任何操作,一旦引起空间的重新配置,指向原vector的所有迭代器就都失效了。

3.2.3 vector容器api

//构造函数
vector<T> v; //采用模板实现类实现,默认构造函数
vector(v.begin(),v.end());//将v[begin,end())区间中的元素拷贝给本身
vector(n,elem);//构造函数将n个elem拷贝给本身
vector(const vector &vec);//拷贝构造函数

//赋值操作
assign(beg,end);//将[beg,end)区间中的数据拷贝赋值给本身
assign(n,elem); //将n个elem拷贝赋值给本身
vector& operator=(const vector &vec);//重载等号操作符
swap(vec);//将vec与本身的元素互换

//大小操作
int size(); //返回容器中元素的个数
bool empty();//判断容器是否为空,返回bool值(0,1)
void resize(int num);//重新指定容器的长度为num,若容器边长,则以默认值填充新位置。若容器变短,则末尾超出容器长度的元素被删除
void resize(int num,elem);//重新指定容器的长度为num,若容器变长,则以elem值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除
int capacity(); //容器的容量
void reserve(int len); //容器预留len个元素长度,预留位置不初始化,元素不可访问。

//取值操作
at(int idx); //返回索引idx所指的数据,如果idx越界,抛出out_of_range异常
operator[](int idx);//返回索引idx所指的数据,越界时,运行直接报错
front(); //返回容器中第一个数据元素
back(); //返回容器中最后一个数据元素

//插入和删除
insert(const_iterator pos,int count,T ele);//迭代器指向位置pos插入count个元素ele
push_back(ele); //尾部插入元素ele
pop_back(); //删除最后一个元素
erase(const_iterator start,const_iterator end);//删除迭代器从start到end之间的元素,删除[start,end)区间的所有元素
erase(const_iterator pos);//删除迭代器指向的元素
clear(); //删除容器中所有元素

巧用swap收缩内存空间

resize()+swap()实现vector收缩内存空间

resize(n);
vector<T>(v).swap(v);

3.3 deque容器

3.3.1 deque基本概念

vector容器是单向开口的连续内存空间,deque则是一种双向开口的连续线性空间。所谓的双向开口,意思是可以在头尾两端分别做元素的插入和删除操作,当然,vector容器也可以在头尾两端插入元素,但是在其头部操作效率奇差,无法被接受。

image-20231124115631599

deque容器和vector容器最大的差异:

1)在于deque允许使用常数项时间对头端进行元素的插入和删除操作
2)在于deque没有容量的概念,因为它是动态的以分段连续空间组合而成,随时可以增加一段新的空间并链接起来
3)deque没有必要要提供所谓的空间保留(reserve)功能
4)虽然deque容器也提供了Random Access Iterator,但是它的迭代器并不是普通的指针,其复杂度和vector不是一个量级,这当然影响各个运算的层面。因此,除非有必要,我们应该尽可能的使用vector,而不是deque
5)对deque进行的排序操作,为了最高效率,可将deque先完整的复制到一个vector中,对vector容器进行排序,再复制回deque。

3.3.2 deque实现原理

逻辑上,deque容器是连续的空间,是由一段一段的定量的连续空间构成。一旦有必要在deque前断或者尾端增加新的空间,便配置一端连续定量的空间,串接在deque的头端或者尾端。

deque最大的工作就是维护这些分段连续的内存空间的整体性的假象,并提供随机存取的接口。

既然deque是分段连续内存空间,那么就必须有中央控制(map实现的),维持整体连续的假象,数据结构的设计及迭代器的前进后退操作颇为繁琐

中央控制:连续小空间,由map实现,存放是地址,地址指向的另一个连续空间为缓冲区。

缓冲区:是deque的存储空间的主体。

image-20231124141345255

3.3.3 常用API

//构造函数
deque<T> deqT;//默认构造形式
deque(beg,end);//构造函数将[beg,end)区间中的元素拷贝给本身
deque(n,elem);//构造函数将n个elem拷贝给本身
deque(const deque &deq);//拷贝构造函数

//赋值操作
assign(beg,end);//将[beg,end)区间中的数据拷贝赋值给本身
assign(n,elem);//将n个elem拷贝赋值给本身
deque& operator=(const deque &deq);//重载等号运算符
swap(deq);//将deq与本身的元素互换

//大小操作
deque.size();//返回容器中元素的个数
deque.empty();//判断容器是否为空
deque.resize(num);//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除
deque.resize(num,elem);//重新指定容器的长度为num,若容器变长,则以elem值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除

//双端插入和删除
void push_back(elem);//在容器尾部添加一个数据
void push_front(elem);//在容器头部插入一个数据
void pop_back();//删除容器最后一个数据
void pop_front();//删除容器第一个数据

//数据存取
at(idx);//返回索引idx所指的数据,如果idx越界,抛出out_of_range
operator[];//返回索引idx所指的数据,如果idx越界,不抛出异常,会直接出错
front();//返回第一个数据
back();//返回最后一个

//插入操作
void insert(iterator pos,T elem);//在pos位置插入一个elem元素的拷贝,返回新数据的位置
void insert(iterator pos,int n,T elem);//在pos位置插入n个elem数据,无返回值
void insert(iterator pos,iter_beg,iter_end);//在pos位置插入[beg,end)区间的数据,无返回值

//删除操作
clear();//移除容器的所有数据
iterator erase(iterator beg,iterator end);//删除[beg,end)区间的数据,返回下一个数据的位置
iterator erase(iterator pos);//删除pos位置的数据,返回下一个数据的位置

3.4 stack容器

3.4.1 stack基本概念

stack是一种先进后出(First in Last Out,FILO)的数据结构,它只有一个出口,stack容器允许新增元素、移除元素、取得栈顶元素,但是除了最顶端外,没有任何其他方法可以存取stack的其他元素,换言之,stack不允许有遍历行为

image-20231124143443033

3.4.2 stack没有迭代器

stack 所有元素的进出都必须符合”先进后出”的条件,只有 stack 顶端的元素,才有机会被外界取用。Stack 不提供遍历功能,也不提供迭代器。

3.4.3 常用API

//构造函数
stack<T> stkT;//stack 采用模板类实现,stack对象的默认构造形式
stack(const stack &stk);//拷贝构造函数

//赋值操作
stack& operator=(const stack &stk);//重载等号操作符

//数据存取
void push(elem);//向栈顶添加元素
void pop();//从栈顶移除第一个元素
T pop();//返回栈顶元素

//大小操作
empty();//判断堆栈是否为空
size();//返回堆栈的大小

3.5 queue容器

3.5.1 queue基本概念

queue是一种先进先出(First in first out,FIFO)的数据结构,它有两个出口,queue容器允许从一端新增元素,从另一端移除元素

image-20231127101407440

3.5.2 queue没有迭代器

queue所有元素的进出都必须符合"先进先出"的条件,只有queue的顶端元素,才有机会被外界取用。queue不提供遍历功能,也不提供迭代器

3.5.3 常用API

//构造函数
queue<T> queT; //queue采用模板类实现,queue对象的默认构造形式
queue(const queue &que); //拷贝构造函数

//存取、插入和删除
void push(elem); //往队尾添加元素
void pop(); //从队头移除第一个元素
T back(); //返回最后一个元素
T front(); //返回第一个元素

//赋值与大小
queue& operator=(const queue &que);//重载等号操作符
empty(); //判断队列是否为空
size(); //返回队列的大小

3.6 list容器

3.6.1 list概念

list(链表)是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的

链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成

每个结点包含两个部分:

1)存储数据元素的数据域
2)存储下一个结点地址的指针域

list与vector的比较:

1)相对于vector的连续线性空间,list就显得负责许多,每次插入或者删除一个元素,就是配置或者释放一个元素的空间,不浪费多余的空间,且插入与移除元素的操作是常数时间(稳定)。
2)list和vector是两个最常被使用的容器,但list是由双向链表实现的
3)list插入操作和删除操作都不会造成原有list迭代器的失效

image-20231127102346533

list特点:

1)采用动态存储分配,不会造成内存浪费和溢出
2)链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素
3)链表灵活,但是空间和时间额外耗费较大

3.6.2 list的迭代器

list不能像vector一样以普通指针作为迭代器,因为其节点不能保证在同一块连续的内存空间上。list迭代器必须有能力指向list的节点,并有能力进行正确的递增、递减、取值、成员存取操作。递增时指向下一个节点,递减时指向上一个节点,取值时取的是节点的数据值,成员取用时取的是节点的成员。另外,list是一个双向链表,迭代器必须能够具备前移、后移的能力,所以list容器提供的是双向的迭代器(bidrectional iterators)

list有一个重要的性质,插入和删除都不会造成原有list迭代器失效

【注】list的迭代器,不支持+n操作

list容器不仅是一个双向链表,而且还是一个循环的双向链表

3.6.3 常用API

//构造函数
list<T> lstT; //list采用模板类实现,对象的默认构造形式
list(beg,end); //构造函数将[beg,end)区间中的元素拷贝给本身
list(n,elem); //构造函数将n个elem拷贝给本身
list(const list &lst); //拷贝构造函数

//插入和删除
push_back(elem); //在容器尾部加入一个元素
pop_back(); //删除容器中最后一个元素
push_front(elem); //在容器开头插入一个元素
pop_front(); //从容器开头移除第一个元素
iterator insert(pos,elem); //在pos位置插elem元素的拷贝,返回新数据的位置
void insert(pos,n,elem); //在pos位置插入n个elem数据,无返回值
void insert(pos,beg,end); //在pos位置插入[beg,end)区间的数据,无返回值
clear(); //移除容器的所有数据
iterator erase(beg,end); //删除[beg,end)区间的数据,返回下一个数据的位置。
iterator erase(pos); //删除pos位置的数据,返回下一个数据的位置
remove(elem); //删除容器中所有与elem值匹配的元素

//大小
size(); //返回容器中元素的个数
empty(); //判断容器是否为空
resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除
resize(num,elem);

//赋值
assign(beg,end); //将[beg,end)区间中的数据拷贝赋值给本身
assign(n,elem); //将n个elem拷贝赋值给本身
list& operator=(const list &lst); //重载等号操作符
swap(lst); //将lst与本身的元素互换

//读取
front(); //返回第一个元素
back(); //返回最后一个元素

//反转和排序
reverse(); //反转链表
sort(); //list排序

3.7 set/multiset容器

3.7.1 set概念

set(集合)的特性是所有元素都会根据元素的键值自动被排序

set的元素即是键值(key)又是实值(value),不允许两个元素有相同的键值

set的iterator是一种const_iterator,不允许修改set的键值

set拥有和list某些相同的性质,当对容器中的元素进行插入操作或者删除操作的时候,操作之前的迭代器,在操作完成之后依然有效,被删除的那个元素的迭代器必然是一个例外。

3.7.2 set数据结构

multiset的特性及用法和set完全相同,唯一的差别在于它允许键值重复。set和multiset的底层实现是红黑树。

3.7.3 常用API

//构造函数
set<T> st; //set默认构造函数
multiset<T> mst; //multiset默认构造函数
set(const set &st); //拷贝构造函数
set(begin,end); //复制[begin,end)区间的数据到当前的集合中

//赋值和大小
set& operator=(const set &st); //重载等号操作符
swap(st); //交换两个集合容器
size(); //返回容器中元素的数目
empty(); //判断容器是否为空

// 插入和删除
insert(elem); //在容器中插入元素
clear(); //清除所有元素
erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器
erase(beg,end); //删除区间[beg,end)的所有元素,返回下一个元素的迭代器
erase(elem); //删除容器中值为elem的元素

//查找
find(key); //查找键key是否存在,若存在,返回该键的元素的迭代器,若不存在,返回set.end();
count(key); //查找键key的元素个数,针对multiset
lower_bound(keyElem); //返回第一个key>=keyElem元素的迭代器
upper_bound(keyElem); //返回第一个key>keyElem元素的迭代器
equal_range(keyElem); //返回容器中key与keyElem相等的上下限的两个迭代器

set排序规则

set自动排序,但可以改变它的排序规则,默认从小到大

自动排序规则,可以使用struct或class,声明bool operator()(v1,v2)仿函数重载

在定义集合时,指定排序规则(类):

set<数据元素的泛型,排序规则类型> s;

3.7.5 对组(pair)

对组(pair)将一对值组合成一个值,这一对值可以具有不同的数据类型,两个值可以分别用pair的两个公有属性first和second访问

类模板:template <class T1,class T2> class pair

用法一:

pair<string,int> pair1(string("name"),20);
cout<<pair1.first<<endl;
cour<<pair1.second<<endl;

用法二:

pair<string,int> pair2=make_pair("name",30);
cout<<pair2.first<<endl;
cout<<pair2.second<<endl;

用法三:

pair<string,int> pair3=pair2; //拷贝构造函数
cout << pair3.first<<endl;
cout << pair3.second<<endl;

3.8 map/multimap容器

3.8.1 map概念

map的特性是所有元素都会根据元素的键值自动排序

map所有的元素都是pair,同时拥有实值和键值,pair的第一元素被视为键值,第二元素被视为实值,map不允许两个元素有相同的键值【键值是唯一的】

multimap和map的操作类型,唯一区别multimap键值可重复

map和multimap都是以红黑树为底层实现机制

【注】map迭代器的元素是pair对组,通过pair对象获取键值(first)和实值(second)

3.8.2 常用API

//构造函数
map<T1,T2> mapTT; //map默认构造函数
map(const map &mp); //拷贝构造函数
map(begin,end); //复制[begin,end)区间的pair对到当前map中

//赋值和大小
map& operator=(const map &mp); //重载等号操作符
swap(mp); //交换两个集合
size(); //返回容器中元素的数目
empty(); //判断容器是否为空

//插入
insert(pair<...>(...)); //往容器中插入元素,返回pair<iterator bool>
insert(make_pair(...))
insert(map<T1,T2>::value_type(...));
T2& operator[](T1 &key);

//删除
clear(); //删除所有元素
erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器
erase(beg,end); //删除区间[beg,end)的所有元素,返回下一个元素的迭代器。
erase(keyElem); //删除容器中key为keyElem的对

//查找
find(key); //查找键key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回map.end();
count(keyElem); //返回容器中key为keyElem的对组个数。对map来说,要么是0,要么是1,对multimap来说,值可能大于1
lower_bound(keyElem); //返回第一个key>=keyElem元素的迭代器
upper_bound(keyElem); //返回第一个key>keyElem元素的迭代器
euqal_range(keyElem); //返回容器中key与keyElem相等的上下限的两个迭代

3.9 STL容器使用时机

3.9.1 结构与操作比较

image-20231127112537795

3.9.2 使用场景

  • vector:如软件历史操作记录的存储,我们经常要查看历史记录,比如上一次的记录,上上次的记录,但却不会去删除记录,因为记录是事实的描述
  • deque:比如排队购票系统,对排队者的存储可以采用deque,支持头端的快速移除,尾端的快速添加。如果采用vector,则头端移除时,会移动大量的数据,速度慢
  • list:比如公交车乘客的存储,随时有可能有乘客下车,支持频繁的不确定位置元素的移除插入
  • set:比如对手机游戏的个人得分记录的存储,存储要求从高分到低分的顺序排列
  • map:比如按ID号存储十万个用户,想要快速通过ID查找对应的用户。二叉树的查找效率,这时就体现出来了。如果是vector容器,最坏的情况下可能要遍历完整个容器才能找到该用户。

4. STL算法

4.1 函数对象

重载函数调用操作符的类,其对象常称为函数对象(function object),即它们是行为类似函数的对象,也叫仿函数(functor),其实就是重载"()"操作符,使得类对象可以像函数那样调用

【注意】

1. 函数对象(仿函数)是一个类,不是一个函数
2. 函数对象(仿函数)重载了"()"操作符使得它可以像函数一样调用

函数对象分类:

一元仿函数(unary_functor),重载的operator()要求获取一个参数
二元仿函数(binary_functor),重载的operator()要求获取两个参数

函数对象的作用:

STL操作的算法往往都有两个版本,其中一个版本表现出最常用的某种运算,另一版本则允许用户通过template参数的形式来指定所要采取的策略

对于template 参数的形式 意思,如指定set的排序规则

set<A,sortA> s;

【总结】

1. 函数对象通常不定义构造函数和析构函数,所以在构造和析构时不会发生任何问题,避免了函数调用的运行时问题
2. 函数对象超出普通函数的概念,函数对象可以有自己的状态
3. 函数对象可内联编译、性能好,用函数指针几乎不可能
4. 模板函数对象使函数对象具有通用性,这也是它的优势之一

4.2 谓词

谓词是指普通函数或重载的operator()返回值是bool类型的函数对象(即仿函数),依据函数接收的参数又分为一元谓词二元谓词等,谓词可作为一个判断式。

4.3 内建函数对象

引入头文件<algorithm>

STL内建了一些函数对象,分为算数函数对象、关系运算类函数对象、逻辑运算类仿函数。这些仿函数所产生的对象,用法和一般函数完全相同,当然我们还可以产生无名的临时对象来履行函数功能

4.3.1 算数类函数对象

6个算数类函数对象,除了negate是一元运算,其他都是二元运算

template<class T> T plus<T>//加法仿函数
template<class T> T minus<T>//减法仿函数
template<class T> T multiplies<T>//乘法仿函数
template<class T> T divides<T>//除法仿函数
template<class T> T modulus<T>//取模仿函数
template<class T> T negate<T>//取反仿函数

4.3.2 关系运算类函数对象

6个关系运算类函数对象,每一种都是二元运算

template<class T> bool equal_to<T>//等于
template<class T> bool not_equal_to<T>//不等于
template<class T> bool greater<T>//大于
template<class T> bool greater_equal<T>//大于等于
template<class T> bool less<T>//小于
template<class T> bool less_equal<T>//小于等于

4.3.3 逻辑运算类运算函数

逻辑运算类运算函数,not为一元运算,其余为二元运算

template<class T> bool logical_and<T>//逻辑与
template<class T> bool logical_or<T>//逻辑或
template<class T> bool logical_not<T>//逻辑非

4.3.4 函数对象适配器

函数适配器bind1st,bind2nd(参数绑定)

1. 函数适配器

1)创建函数对象类,继承binary_function<T1,T2,T3>,声明()重载,其中T1、T2是重载函数的2个参数,T3为重载函数的返回值类型

【注】定义public的()重载时,必须由const修饰

2)应用函数适配器

for_each(v.begin(),v.end(),bind1st(函数对象类(),x));
for_each(v.begin(),v.end(),bind2nd(函数对象类(),x));

bind1st和bind2nd的区别

bind1st:将参数绑定为函数对象的第一个参数
bind2nd:将参数绑定为函数对象的第二个参数
bind1st和bind2nd 将二元函数对象转为一元函数对象
2. 取反适配器

1)定义unary_function<int,bool>的函数对象类

2)应用

find_if(v.begin(),v.end(),函数对象类());
find_if(v.begin(),v.end(),not1(函数对象类())); 
//动态给定条件
find_if(v.begin(),v.end(),nto1(bind2nd(greater<int>(),5)));
sort(v.begin(),v.end(),not2(less<int>()));
//匿名函数
for_each(v.begin(),v.end(),[](int val){cout<<cal<<" ";});

其中的 not1 对一元函数对象取反, not2 对二元函数对象取反。

3. 函数指针适配器

应用ptr_fun()

【注】仿函数的参数不能使用引用

4. 成员函数适配器

应用mem_fun_ref()

成员函数作为仿函数时,则通过容器成员调用它的仿函数

4.4 算法应用

算法中常用的功能涉及到比较、交换、查找、遍历、复制、修改、反转、排序、合并等

4.4.1 常用遍历算法

for_each(iterator beg,iterator end,_callback);
/*
遍历算法 遍历容器元素
@param beg 开始迭代器
@param end 结束迭代器
@param _callback 函数回调或者函数对象
@return 函数对象
*/

transfrom(iterator beg1,iterator end1,iterator beg2,_callback);
/*
@param beg1 源容器开始迭代器
@param end1 源容器结束迭代器
@param beg2 目标容器开始迭代器
@param _callback 回调函数或者函数对象
@return 返回目标容器迭代器
*/
将指定容器区间元素搬运到另一容器中
【注】不会给目标容器分配内存,所以需要我们提前分配好内存

4.4.2 常用查找算法

find(iterator beg,iterator end,value);
/*
find 算法 查找元素
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param value 查找的元素
@return 返回查找元素的位置
*/

find_if(iterator beg,iterator end,_callback);
/*
find_if 算法 条件查找
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param callback 回调函数或者谓词(返回 bool 类型的函数对象)
@return 返回查找元素的位置
*/

adjacent_find(iterator beg,iterator end,_callback);
/*
adjacent_find 算法 查找相邻重复元素
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param _callback 回调函数或者谓词(返回 bool 类型的函数对象)
@return 返回相邻元素的第一个位置的迭代器
*/

bool binary_search(iterator beg,iterator end,value);
/*
binary_search 算法 二分查找法
注意: 在无序序列中不可用
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param value 查找的元素
@return bool 查找返回 true 否则 false
*/

count(iterator beg,iterator end,value);
/*
count 算法 统计元素出现次数
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param value 回调函数或者谓词(返回 bool 类型的函数对象)
@return int 返回元素个数
*/

count_if(iterator beg,iterator end,value);
/*
count_if 算法 统计元素出现次数
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param callback 回调函数或者谓词(返回 bool 类型的函数对象)
@return int 返回元素个数
*/

4.4.3 常用排序算法

merge(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest);
/*
merge 算法 容器元素合并,并存储到另一容器中
注意:两个容器必须是有序的
@param beg1 容器 1 开始迭代器
@param end1 容器 1 结束迭代器
@param beg2 容器 2 开始迭代器
@param end2 容器 2 结束迭代器
@param dest 目标容器开始迭代器
*/

sort(iterator beg,iterator end,_callback);
/*
sort 算法 容器元素排序
@param beg 容器 1 开始迭代器
@param end 容器 1 结束迭代器
@param _callback 回调函数或者谓词(返回 bool 类型的函数对象)
*/

random_shuffle(iterator beg,iterator end);
/*
random_shuffle 算法 对指定范围内的元素随机调整次序
@param beg 容器开始迭代器
@param end 容器结束迭代器
*/

reverse(iterator beg,iterator end);
/*
reverse 算法 反转指定范围的元素
@param beg 容器开始迭代器
@param end 容器结束迭代器
*/

4.4.4 常用拷贝和替换算法

copy(iterator beg,iterator end,iterator dest);
/*
copy 算法 将容器内指定范围的元素拷贝到另一容器中
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param dest 目标起始迭代器
*/

replace(iterator beg,iterator end,oldvalue,newvalue);
/*
replace 算法 将容器内指定范围的旧元素修改为新元素
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param oldvalue 旧元素
@param oldvalue 新元素
*/

replace_if(iterator beg,iterator end,_callback,newvalue);
/*
replace_if 算法 将容器内指定范围满足条件的元素替换为新元素
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param callback 函数回调或者谓词(返回 Bool 类型的函数对象)
@param oldvalue 新元素
*/

swap(container c1,container c2);
/*
swap 算法 互换两个容器的元素
@param c1 容器 1
@param c2 容器 2
*/

4.4.5 常用算术生成算法

引入<numeric>头文件

accumlate(iterator beg,iterator end,value);
/*
accumulate 算法 计算容器元素累计总和
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param value 累加值, 额外加的值,可以为0
@return 累加后的数值
*/

fill(iterator beg,iterator end,value);
/*
fill 算法 向容器中添加元素
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param value t 填充元素
*/

4.4.6 常用集合算法

set_intersection(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest);
/*
set_intersection 算法 求两个 set 集合的交集
注意:两个集合必须是有序序列
@param beg1 容器 1 开始迭代器
@param end1 容器 1 结束迭代器
@param beg2 容器 2 开始迭代器
@param end2 容器 2 结束迭代器
@param dest 目标容器开始迭代器
@return 目标容器的最后一个元素的迭代器地址
*/

set_union(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest);
/*
set_union 算法 求两个 set 集合的并集
注意:两个集合必须是有序序列
@param beg1 容器 1 开始迭代器
@param end1 容器 1 结束迭代器
@param beg2 容器 2 开始迭代器
@param end2 容器 2 结束迭代器
@param dest 目标容器开始迭代器
@return 目标容器的最后一个元素的迭代器地址
*/

set_difference(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest);
/*
set_difference 算法 求两个 set 集合的差集
注意:两个集合必须是有序序列
@param beg1 容器 1 开始迭代器
@param end1 容器 1 结束迭代器
@param beg2 容器 2 开始迭代器
@param end2 容器 2 结束迭代器
@param dest 目标容器开始迭代器
@return 目标容器的最后一个元素的迭代器地址
*/

标签:容器,end,迭代,iterator,stl,元素,param,标准
From: https://www.cnblogs.com/dijun666/p/17859410.html

相关文章

  • C++标准库函数std::async
    1、std::asyncstd::async是C++11的标准库函数,用于创建执行异步任务并返回std::future对象来获取异步执行的结果状态。该函数最简单的用法如下所示:#include<iostream>#include<thread>#include<future>std::stringpromise_string(){for(inti=0;i<200;......
  • 标准程序ALV增强思路
    一选择屏幕默认值首先在初始化部分后面找一个隐士点做默认值值赋值要去定义部分看下选择屏幕是哪个例如这里是ST_WERKSAPPENDVALUE#(SIGN='I'option='EQ'LOW='A101')TOST_WERKS. 二如果需要对取数后的屏幕字段做修改 START-OF-SELECTION之后找一个隐士点......
  • 实验4 现代C++标准库与类模板
    实验任务5TextCoder.hpp源码1#include<iostream>2#include<string>34usingstd::string;56classTextCoder{7private:8stringtext;9voidencoder();10voiddecoder();11public:12TextCod......
  • 队列(最基本队列,标准队列 2个,双端队列,单调队列)
    2023-11-26最基本队列:一次性使用的classQueue01{//最基本队列,一次性的,数组模拟,先进先出//功能:入队,出队,判满,判空,显示队头,显示队列privateint[]queue;privateintfront=-1;//指向第一个元素前一个位置privateinttail=-1;//指向最后一个元素p......
  • 01-前言&WEB标准
    .typora-copy-images-to:media第01阶段.前端基础.认识WEB基础班学习目标目标:能根据psd文件,用HTML+CSS布局出符合W3C规范的网页。网站首页列表页、详情页、登录页、注册页等等。。。。课程安排就业班详情参看:http://www.itcast.cn/course/web.shtmlHTML第一......
  • [机翻]Fun With Another PG-Compliant Hook/另一个符合 PG 标准的钩子的乐趣
    原文链接:https://revers.engineering/fun-with-pg-compliant-hook/目录Overview/概述CommonHookPointsinWindowsKernel/Windows内核中的常见钩子点TheHalPrivateDispatchTableTargetDiscovery/目标发现DIY…MOSTLYDIY.../主要δLocatingHalPrivateDispatchTable/......
  • ACM常用STL函数
    max()min()找多个元素的最大值和最小值max(a,b)比较两个元素mx=max({a,b,c,d});比较多个元素lower_bound()upper_bound()寻找第序列第n小的值的地址//在a数组中查找第一个大于等于x的元素,返回该元素的地址int*p=lower_bound(a,a+n,x);//在a数组中查找第一个大于x......
  • 常用STL
    vector(动态数组)vector为可变长数组(动态数组),定义的vector数组可以随时添加数值和删除元素。需要的头文件vector。定义和使用初始化//方式一:通过下标访问,假设num数组中已经有了5个元素cout<<num[4]<<"\n";//输出第五个数据//一二维可变数组和普通数组的访问方法一样//方......
  • Go标准库学习:strings和bytes
    strings包和bytes包strings包和bytes包非常像,几乎所有函数都有string和[]byte两种接口,其中前者被实现在strings包中,而后者被是现在bytes包中,所以这里将这两个包一起学习。官方文档:strings包:https://pkg.go.dev/[email protected]包:https://pkg.go.dev/[email protected]函数......
  • SAP集成技术(六)技术、标准和协议
    本文链接:https://www.cnblogs.com/hhelibeb/p/17849837.html内容摘录自《SAPInterfaceManagementGuide》。WebServiceWebService是互联网或企业网络中的平台-无关的服务,通过该服务,应用程序可以使用标准的网络技术与先前定义的接口交换信息。术语的定义如此,但是,具体的含义......