STL
Standard Template Library,标准模板库
六大组件
- 容器:存放数据
- 算法:操作数据
- 迭代器:算法通过迭代器操作容器数据
- 仿函数:为算法提供更多的策略
- 适配器:为算法提供更多参数的接口
- 空间配置器:为算法和容器动态分配、管理空间
重要特性:数据和操作分离。数据由容器管理,操作由特定的算法完成。容器和迭代器一一对应
算法分为质变算法和非质变算法:
质变算法:运算过程中会改变区间内的元素的内容,如拷贝、替换、删除等;
非质变算法:运算过程中不会改变区间内的元素的内容,如查找、计数、遍历、寻找极值等;
string类
string封装了char *,用于管理字符串,是一个char型的容器
string类自动管理char *分配的内存。不用考虑内存释放和越界,每一次string的复制,都有string类负责维护
string构造函数
string();//创建一个空的字符串 例如: string str;
string(const string& str);//使用一个 string 对象初始化另一个 string 对象
string(const char* s);//使用字符串 s 初始化
string(int n, char c);//使用 n 个字符 c 初始化
string基本赋值操作
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 个字符赋值给字符串
string存取字符操作
char& operator[](int n);//通过[]方式取字符
char& at(int n);//通过 at 方法获取字符
string str = "helloc";
str[1] = 'E';
str.at(1) = 'E';
在QT中[]越界不会抛出异常,at方法越界会抛出异常。[]执行str[7]=‘A’,可以正常输出helloc
string 拼接操作
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
string的查找和替换
int find(const string& str, int pos = 0) const; //查找 str 第一次出现位置, 从 pos 开始查找
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; //查找字符 c 第一次出现位置
int rfind(const string& str, int pos = npos) const;//查找 str 最后一次位置, 从 pos开始查找
int rfind(const char* s, int pos = npos) const;//查找 s 最后一次出现位置,从pos 开始查找
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
string比较操作
//compare 函数在>时返回 1,<时返回 -1,==时返回 0。
int compare(const string &s) const;//与字符串 s 比较
int compare(const char *s) const;//与字符串 s 比较,重载了> < ==等关运算符
string 子串
string substr(int pos = 0, int n = npos) const;//返回由 pos 开始的 n 个字符组成的字符串
string 插入和删除操作
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 个字符
string 和 c-style 字符串转换
//string 转 char*
string str = "itcast";
const char* cstr = str.c_str();
//char* 转 string
char* s = "itcast";
string str(s);
vector容器
vector与数组相似,最大的特点是在于空间的灵活使用
vector单端操作,只能在一端增删
v.begin():获取容器的起始迭代器(指向第0个元素)
v.end():获取容器的结束迭代器(指向最后一个元素的下一个位置)
vector的数据结构
线性连续空间,两个迭代器Myfirst和Mylast分别指向目前已被使用的范围,迭代器_Myend指向整块连续空间内存的尾端
以备需要,vector实际配置的大小可能会大于需要的大小,一旦容量满,整个vector就需要寻找一块更大的连续空间,然后将数据拷贝过去。并且原来的迭代器全部失效
vector构造函数
vector<T> v; //采用模板实现类实现,默认构造函数
vector(v.begin(), v.end());//将 v[begin(), end())区间中的元素拷贝给本身。
vector(n, elem);//构造函数将 n 个 elem 拷贝给本身。
vector(const vector &vec);//拷贝构造函数。
迭代器
vector<int>::iterator it = v.begin();//定义一个迭代器保存起始迭代器
for(; it!=v.end();it++) cout<<*it<<" ";//遍历容器
查看vector的内存管理机制:开辟新的空间
每次开辟空间:(1)重新找一块内存;(2)capacity变为原来的2倍
vector<int> v;
cout<<v.capacity()<<" "<<v.size()<<endl;//输出 0 0
vector<int>::iterator it;
for(int i=0; i<5; ++i){
v.push_back(i);
if(it != v.begin()){//每一次v.begin()迭代器都会改变。说明vector的内存地址变了
cout<<v.capacity()<<endl;//一共执行了4次,分别输出1,2,4,8
it = v.begin();
}
}
预先设定空间
v.reserve(1000);
vector常用赋值操作
assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。这里的beg和end要是迭代器
assign(n, elem);//将 n 个 elem 拷贝赋值给本身。
vector& operator=(const vector &vec);//重载等号操作符
swap(vec);// 将vec与本身的元素互,v2.swap(v1);将v1和v2交换
遍历容器
printVector(vector<int> &v){
vector<int>::iterator it = v.begin();
for(;it!=v.end();it++){
cout<<*it<<" ";
}
cout<<endl;
}
也可以像数组那样遍历
vector大小操作
size();
empty();
resize(int num);//以默认值填充新位置,默认值为0
resize(int num, elem);//以elem填充新位置
capacity();
reserve(int len);//预留len个元素长度,预留位置不初始化,元素不可访问
//resize会打印总的num个元素,而reserve只会打印已有的元素
vector数据存取操作
at(int idx);
operator[];
front();
back();
vector插入和删除
insert(const_iterator pos, int count, elem);//迭代器指向位置pos,插入count个elem;pos会被后移
push_back(elem);//尾部插入
pop_back(elem);//尾部删除
erase(const_iterator start, const_iterator end);//区间删除
erase(const_iterator pos);//删除迭代器所指元素
clear();//删除所有;
swap收缩空间
resize不能缩小capacity,只能改变size或增大capacity
vector<int> v;
v.reserve(100);
vector<int> (v).swap(v);//(v)表示匿名对象
v1是旧对象,vector()是新的匿名对象,旧对象拷贝给匿名对象期间发生拷贝构造。匿名对象拷贝只会拷贝有数据的区间
然后匿名对象和v发生交换,于是v就只包含有效数据部分
匿名对象生命周期为当前语句,语句结束,匿名对象就被释放了
vector容器嵌套
vector<vector<int>> v;//定义
//遍历
vector<vector<int>>::iterator it = v.begin();
for(; it!=v.end(); it++){
vector<int>::iterator mit = (*it).begin();
for(; mit!=(*it).end(); ++mit){
cout<<*mit<<" ";
}
cout<<endl;
}
vector和自定义类型
重载运算符或设置友元
案例:对自定义类型进行排序
sort(v1.begin(), v1.end(), comparePerson);//comparePerson为自定义排序规则
class Person{
friend bool comparePerson(Person ob1, Person ob2);
friend void printVector(vector<Person> &v);
private:
int num;
string name;
public:
Person(int num, string name){
this->num = num;
this->name = name;
}
};
bool comparePerson(Person ob1, Person ob2){
return ob1.num<ob2.num;
}
void printVector(vector<Person> &v){
vector<Person>::iterator it = v.begin();
for(;it!=v.end();it++){
cout<<(*it).num<<" "<<(*it).name<<endl;
}
}
int main(void){
vector<Person> v;
v.push_back(Person(3, "lucy"));
v.push_back(Person(7, "bob"));
v.push_back(Person(1, "tom"));
printVector(v);
sort(v.begin(), v.end(), comparePerson);//需要引入<algorithm>
printVector(v);
return 0;
}
deque容器
#include <deque>
和vector的区别:
(1)允许两端插入和删除(vector也可以在头部插入,但效率奇差)
(2)deque的空间不连续,由多段定量的连续空间组合。因此deque没有reserve功能
(3)deque的迭代器不是普通指针,复杂度比vector高,应当尽可能使用vector
(4)如有需要,如在排序时候,可以将deque复制给vector,排完序后再复制回来
(5)deque最大的工作是维护多段空间的整体,提供随机存取的接口。避开了重新配置空间、复制和释放,但代价是复杂的迭代器架构
deque原理:
以一个map作为中控器
每一个map元素存放一个指针,指向一段连续内存空间。这些连续内存空间被称为缓冲区。缓冲区才是deque存储主体
deque构造函数
deque <T> deqT;
deque(beg, end);
deque(n, elem);
deque(const deque &deq);
deque赋值操作
assign(beg, end);
assign(n, elem);
deque& operator=(const deque &deq);
swap(dep);
deque大小操作
deque.size();
deque.empty();
deque.resize(num);//默认值填充
deque.resize(num, elem);
deque插入和删除
//双端操作
push_back(elem);//尾端插入
push_front(elem);//头部插入
pop_back();//尾部删除
pop_front();//头部删除
//插入:pos beg end都是迭代器
insert(pos, elem);
insert(pos, n, elem);//插入n个elem;
insert(pos, beg, end);
//删除
clear();
erase(beg, end);
erase(pos);
deque数据存取
at(idx);
operator[];
front();//返回第一个元素
back();//返回最后一个元素
案例
有 5 名选手:选手 ABCDE,10 个评委分别对每一名选手打分,去除最高分,去除评委中最低分,取平均分。
- 创建五名选手,放到 vector 中
- 遍历 vector 容器,取出来每一个选手,执行 for 循环,可以把 10 个评分打分存到 deque 容器中
- sort 算法对 deque 容器中分数排序,pop_back pop_front 去除最高和最低分
- deque 容器遍历一遍,累加分数,累加分数/d.size()
- person.score = 平均分
#include<iostream>
#include<vector>
#include<deque>
#include<algorithm>
#include<time.h>
using namespace std;
class Person{
friend void showPerson(vector<Person> &v);
friend void playGame(vector<Person> &v);
private:
string name;
float score;
public:
Person(string name, float score){
this->score = score;
this->name = name;
}
};
void showPerson(vector<Person> &v){
vector<Person>::iterator it = v.begin();
for(;it!=v.end();it++){
cout<<(*it).name<<" "<<(*it).score<<endl;
}
}
void createPerson(vector<Person>& v){
string tmpName = "ABCDE";
for(int i=0; i<5; ++i){
string name = "选手";
name+=tmpName[i];
v.push_back(Person(name, 0.0f));
}
}
void playGame(vector<Person> &v){
vector<Person>::iterator it = v.begin();
for(; it!=v.end(); it++){
deque<float> d;
for(int i=0; i<10; ++i){
d.push_back((float)(rand()%41+60));//1.输入成绩
}
sort(d.begin(), d.end());//2.排序
d.pop_back();
d.pop_front();//3.去掉最高分和最低分
(*it).score = (float)accumulate(d.begin(), d.end(), 0)/d.size();
}
}
int main(void){
vector<Person> v;
srand(time(NULL));
createPerson(v);//创建选手
playGame(v);
showPerson(v);
return 0;
}
stack容器
//1. stack构造函数
stack<T> stkT;
stack(const stack &stk);
//2. stack赋值操作
stack& operator=(const stack &stk);
//3. stack数据存取
push(elem);
pop();
top();
//4. stack大小操作
empty();
size();
queue容器
queue不提供遍历功能,也不提供迭代器
//1. queue构造函数
queue<T> queT;
queue(const queue &que);
//2. queue赋值操作
queue& operator=(const queue& que);
//2. queue数据存取
push(elem);//队尾添加元素
pop();//队首移除
back();//返回最后一个元素,但不删除
front();//返回第一个元素,但不删除
//4. queue大小操作
empty();
size();
list链表容器
!!list容器是一个双向链表
list容器的迭代器是双向迭代器,不支持+n,但支持++
list构造函数
list<T> lstT;
list(begin, end);
list(n, elem);
list(const list &lst);
list插入和删除
push_back(elem);
pop_back();
push_front(elem);
pop_front();
insert(pos, elem);
insert(pos, n, elem);
insert(pos, beg, end);
clear();
erase(beg, end);
erase(pos);
remove(elem);//删除所有和elem值匹配的元素
list大小操作
size();
empty();
resize(num);
resize(num, elem);
list赋值操作
assign(beg, end);
assign(n, elem);
list& operator=(const list &lst);
swap(list);
list数据存取
front();
back();
list反转数据
reverse();
sort();
set/multiset容器
!!所有元素都会根据元素的键值自动被排序,set的元素既是键值,又是实值
set不允许出现相同的键值
multiset特性和用法与set完全相似,但multiset允许键值重复
set的迭代器是只读迭代器,不允许修改键值
set构造函数
set<T> st;
multiset<T> mst;
set(const set &st);
set赋值操作
set& operator=(const set &st);
swap(st);
set大小操作
size();
empty();
set插入和删除
insert(elem);
erase(pos);//pos指迭代器,返回下一个元素的迭代器
erase(beg, end);
erase(elem);//删除容器中为elem的元素
要修改排序规则,必须在插入之前修改,要使用仿函数
仿函数:重载函数调用运算符()的类
set查找操作
find(key);//查找key是否存在,存在返回该键元素的迭代器,不存在返回set.end();
cout(key);//查找键key的元素的个数,0或者1
lower_bound(keyElem);//返回keyElem的元素,如果没有就返回在它后边一个位置的迭代器
upper_bound(keyElem);//返回keyElem的后边一个元素的迭代器
equal_range(keyElem);
//注意lower_bound,upper_bound,equal_range返回迭代器是指位置,而不是本身大小。如果没有符合条件的,就返回keyElem本身
equal_range返回两个迭代器,分别是lower_bound和upper_bound,需要用pair去接
//equal_range以对组的方式接返回值
pair<set<int>::const_iterator, set<int>::const_iterator> pa;
pa = st.equal_range(6);
cout<<*(pa.first)<<endl;
cout<<*(pa.second)<<endl;
修改排序规则
//仿函数:重载函数调用调用运算符()的类
class MyGreater{
public:
bool operator()(int v1, int v2){
return v1>v2;
}
};
void printSet(set<int, MyGreater> &s){
set<int, MyGreater>::const_iterator it = s.begin();
for(; it!=s.end(); it++){
cout<<*it<<" ";
}
cout<<endl;
}
int main(void){
set<int, MyGreater> st;
st.insert(7);
st.insert(5);
st.insert(6);
printSet(st);
return 0;
}
自定义类必须修改排序规则
class MyGreaterPerson;
class Person{
friend MyGreaterPerson;
friend void printPersonSet(set<Person, MyGreaterPerson> &st);
private:
int num;
string name;
public:
Person(int num, string name){
this->name = name;
this->num = num;
}
};
//自定义类必须修改排序规则
class MyGreaterPerson{
public:
bool operator()(Person ob1, Person ob2){
return ob1.num < ob2.num;
}
};
void printPersonSet(set<Person, MyGreaterPerson> &st){
set<Person, MyGreaterPerson>::const_iterator it = st.begin();
for(; it!=st.end(); it++){
cout<<(*it).num<<" "<<(*it).name<<endl;
}
}
int main(void){
set<Person, MyGreaterPerson> st2;
st2.insert(Person(9, "lucy"));
st2.insert(Person(4, "bob"));
st2.insert(Person(7, "tom"));
printPersonSet(st2);
return 0;
}
pair对组
pair<int, string> p1(10086, "移动");
pair<int, string> p2 = make_pair(110, "报警");//推荐
cout<<p2.first<<endl;
cout<<p2.second<<endl;
map/multimap容器
map的所有元素都是对组,pair的第一元素是键值,第二元素是实值;
map不允许有相同的键值,键值自动排序
不能通过迭代器修改map的键值,但可以修改实值
multimap与map唯一不同的地方是,multimap键值可重复
multimap和map底层都是以红黑树实现的
map构造函数
map<T1, T2> mapTT;
map(const map &mp);
map赋值操作
map& operator=(const map &mp);
swap(map);
map大小操作
size();
empty();
map插入和删除
//通过pair插入
insert(pair<T1, T2>(elem1, elem2));
insert(make_pair(elem1, elem2));
//通过value_type插入
insert(map<T1, T2>::value_type(elem1, elem2));
//通过数组的方式插入
mp[key] = value;
//删除
clear();
erase(pos);
erase(beg, end);
erase(keyElem);//删除容器中key为keyElem的对组
map查找操作
find(key);//查找key是否存在,存在则返回元素迭代器,不存在则返回map.end();
count(keyElem);//计算key为keyElem的对组个数;对map来说是0或1,多multimap来说可能大于1
lower_bound(keyElem);
upper_bound(keyElem);
equal_range(keyElem);//这三个函数与set中的含义一致
!!使用数组的方法去操作map会比较危险,不存在时会自动创建一个key
5个人,3个部门,要求按部门展示人
思路:vector存储5个人的信息
multimap存放对组pair(部门,vector.iterator)
find找到multimap中部门的起始迭代器
count计算有该部门下有多少人
各个容器的使用场景
- vector 的使用场景:比如软件历史操作记录的存储,我们经常要查看历史记录,比如上一次的记录,上上次的记录,但却不会去删除记录,因为记录是事实的描述。
- deque 的使用场景:比如排队购票系统,对排队者的存储可以采用 deque,支持头端的快速移除,尾端的快速添加。deque 支持头部的快速插入与快速移除,这是 deque 的优点。
- list 的使用场景:比如公交车乘客的存储,随时可能有乘客下车,支持频繁的不确实位置元素的移除插入。
- set 的使用场景:比如对手机游戏的个人得分记录的存储,存储要求从高分到低分的顺序排列。
- map 的使用场景:比如按 ID 号存储十万个用户,想要快速要通过 ID 查找对应的用户。map利用二叉树,查找效率快。如果是vector 容器,最坏的情况下可能要遍历完整个容器才能找到该用户。
STL算法
仿函数
像函数调用那样使用类,需要重写()运算符
class Print{
public:
void operator()(char *str){
cout<<str<<endl;
}
};
void test(){
Print ob;
ob("helloc!");//重写()运算符,形成函数调用的形式,被称为函数对象(仿函数)
}
如果函数对象有1个参数,被称为一元函数对象
如果函数对象有2个参数,被称为二元函数对象
如果函数对象有多个参数,被称为多元函数对象
函数对象通常不定义构造函数和析构函数,因此在构造和析构上不会发生问题
函数对象超出普通函数的概念,函数对象可以有自己的状态
函数对象可内敛编译,性能好。用函数指针几乎不可能
函数对象可采用模板函数,使其具有通用性
谓词(修改规则)
返回值类型为bool型的普通函数或仿函数,都叫谓词
如果谓词有1个参数,叫一元谓词
如果谓词有2个参数,叫二元谓词
- 一元谓词
bool over30(int value){
return value > 30;
}
class Over30{
public:
bool operator()(int value){
return value > 30;
}
};
//普通函数提供策略
ret = find_if(v.begin(), v.end(), over30);
//仿函数提供策略
ret = find_if(v.begin(), v.end(), Over30());//形成一个匿名对象
- 二元谓词
bool over30(int v1, int v2){
return v1 > v2;
}
class Over30{
public:
bool operator()(int v1, int v2){
return v1 > v2;
}
};
//普通函数提供策略
sort(v.begin(), v.end(), over30);
//仿函数提供策略
sort(v.begin(), v.end(), Over30());
内建函数对象
STL内建了一些函数对象,这些仿函数所产生的对象,用法和一般函数相同
- 6个算术类函数对象
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>//取反仿函数
- 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>//小于等于
- 逻辑运算,not为一元,其余为二元运算
template<class T> bool logical_and<T>//逻辑与
template<class T> bool logical_or<T>//逻辑或
template<class T> bool logical_not<T>//逻辑非
- 使用
sort(v.begin(), v.end(), greater<int>());//不用使用仿函数,使用内建函数就可以重写修改规则
ret = find_if(v.begin(), v.end(), bind2nd(greater<int>(),10));//find_if只有3个参数,因此需要用bind绑定一下
适配器
函数对象适配器
class PrintInt{
public:
void operator()(int val){
cout<<val+100<<" ";
}
};
for_each(v.begin(), v.end(), PrintInt());//需要自定义规则
cout<<endl;
进一步:绑定参数
//2. 公共继承binary_function 参数萃取
class PrintInt:public binary_function<int, int, void>{
public:
//3. 用const修饰operator()
void operator()(int val, int tmp) const{
cout<<val+tmp<<" ";
}
};
void test(){
vector<int> v;
v.push_back(10);
v.push_back(6);
v.push_back(20);
//1. bind2nd或bind1st绑定参数
for_each(v.begin(), v.end(), bind2nd(PrintInt(), 200));
cout<<endl;
}
bind1st是绑定到第一个参数val上面,bind2nd是绑定到第二个参数tmp上面
函数指针适配器
void myPrintInt(int value, int tmp){
cout<<value+tmp<<" ";
}
for_each(v.begin(), v.end(), bind2nd(ptr_fun(myPrintInt), 200));
cout<<endl;
成员函数作为适配器
class Data{
public:
void printInt(int tmp){
cout<<value+tmp<<" ";
}
}
for_each(v.begin(), v.end(), bind2nd(mem_fun_ref(&Data::printInt), 100));
取反适配器
- 一元取反
ret = find_if(v.begin(), v.end(), not1(bind2nd(greater<int>(), 30)));//找出第一个小于等于30
- 二元取反
//lambda表达式,c++11开始支持
//[] lambda不能读写;[=] lambda对数据进行读操作;[&] lambda对数据进行读写操作
//
for_each(v.begin(), v.end(), [&](int val){
cout<<val<<" ";
});
cout<<endl;
sort(v.begin(), v.end(), not2(greater<int>()));//greater需要2个参数比较,因此使用not2
常用算法
for_each
for_each(iterator beg, iterator end, _callback);
transform
将指定容器区间元素搬运到另一容器中
transform不会给目标容器分配内存,因此需要自行提前分配内存
@param beg1 源容器开始迭代器
@param end1 源容器结束迭代器
@param beg2 目标容器开始迭代器
@param _cakkback 回调函数或者函数对象
@return 返回目标容器迭代器
transform(iterator beg1, iterator end1, iterator beg2, _callback);
int myTransform(int value){
return value;
}
v2.resize(v1.size());
transform(v1.begin(), v1.end(), v2.begin(), myTransform);
find
find(iterator beg, iterator end, iterator, value);//未找到返回v.end()
find_if
find_if(iterator beg, iterator end, _callback);//条件查找
ret = find_if(v.begin(), v.end(), bind2nd(greater<int>(),30));//找不到返回v.end();
adjacent_find
//@reurn 返回相邻元素的第一个位置的迭代器
adjacent_find(iterator beg, iterator end, _callback);
binary_search
//二分查找,必须有序
bool binary_search(iterator beg, iterator end, value);
count
//统计元素出现的次数,返回int
count(iterator beg, iterator end, value);
count_if
//按条件查找
count_if(iterator beg, iterator end, _callback);
count_if(v.begin(), v.end(), bind2th(greater<int>(), 10));//返回大于10的个数
常用排序算法
merge
//将两个容器,合并并存储到另一个容器中
//需要事先为第三个容器开辟空间
merge(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);//dest目标容器起始迭代器
sort
sort(iterator beg, iterator end, _callback);
random_shuffle
//对指定范围内的元素随机调整次序
random_shuffle(iterator beg, iterator end);
//使用
srand(time(NULL));
random_shuffle(v.begin(), v.end());
reverse
reverse(iterator beg, iterator end);
常用拷贝替换算法
copy
//拷贝,将一个容器中的数据拷贝到另一个容器,但不会自动分配内存
copy(iterator beg, iterator end, iterator dest.beg);
拷贝到终端
copy(iterator beg, iterator end, ostream_iterator<int>(cout, " "));//" "是连接符
replace
replace(iterator beg, iterator end, oldValue, newValue);
replace(v.begin(). v.end(), 30, 3000);//将30替换为3000
replace_if
replace_if(iterator beg, iterator end, _callback, newValue);
示例
class Greater30{
public:
bool operator()(int val){
return val>30;
}
};
replace_if(v.begin(), v.end(), Greater30(), 2000);//除了仿函数,还可以使用内建函数、普通函数等
swap
swap(container c1, container c2);//交换两个容器
常用算数生成算法
accumulate
//累计求和
accumulate(iterator beg, iterator end, value);//value表示累计求和之后的值加上value
fill
fill(iterator beg, iterator end, value);//用value填充区间值
常用集合算法
set_intersection
//求两个集合的交集,结果保存在另一个集合中
//集合必须是有序序列
set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest.beg);
示例
v3.resize(min(v1.size(), v2.size()));
vector<int>::iterator ret;
ret = set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
copy(v3.begin(), ret, ostream_iterator<int>(cout, " "));
cout<<endl;
set_union
//集合求并集
set_union(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest.beg);
set_difference
//集合求差集
set_difference(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest.beg);