5. STL容器和算法使用

STL

Standard Template Library,标准模板库

六大组件

  1. 容器:存放数据
  2. 算法:操作数据
  3. 迭代器:算法通过迭代器操作容器数据
  4. 仿函数:为算法提供更多的策略
  5. 适配器:为算法提供更多参数的接口
  6. 空间配置器:为算法和容器动态分配、管理空间

重要特性:数据和操作分离。数据由容器管理,操作由特定的算法完成。容器和迭代器一一对应

算法分为质变算法和非质变算法:
质变算法:运算过程中会改变区间内的元素的内容,如拷贝、替换、删除等;
非质变算法:运算过程中不会改变区间内的元素的内容,如查找、计数、遍历、寻找极值等;

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 个评委分别对每一名选手打分,去除最高分,去除评委中最低分,取平均分。

  1. 创建五名选手,放到 vector 中
  2. 遍历 vector 容器,取出来每一个选手,执行 for 循环,可以把 10 个评分打分存到 deque 容器中
  3. sort 算法对 deque 容器中分数排序,pop_back pop_front 去除最高和最低分
  4. deque 容器遍历一遍,累加分数,累加分数/d.size()
  5. 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计算有该部门下有多少人

各个容器的使用场景

  1. vector 的使用场景:比如软件历史操作记录的存储,我们经常要查看历史记录,比如上一次的记录,上上次的记录,但却不会去删除记录,因为记录是事实的描述。
  2. deque 的使用场景:比如排队购票系统,对排队者的存储可以采用 deque,支持头端的快速移除,尾端的快速添加。deque 支持头部的快速插入与快速移除,这是 deque 的优点。
  3. list 的使用场景:比如公交车乘客的存储,随时可能有乘客下车,支持频繁的不确实位置元素的移除插入。
  4. set 的使用场景:比如对手机游戏的个人得分记录的存储,存储要求从高分到低分的顺序排列。
  5. 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个参数,叫二元谓词

  1. 一元谓词
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());//形成一个匿名对象
  1. 二元谓词
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内建了一些函数对象,这些仿函数所产生的对象,用法和一般函数相同

  1. 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>//取反仿函数
  1. 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>//小于等于
  1. 逻辑运算,not为一元,其余为二元运算
template<class T> bool logical_and<T>//逻辑与
template<class T> bool logical_or<T>//逻辑或
template<class T> bool logical_not<T>//逻辑非
  1. 使用
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));

取反适配器

  1. 一元取反
ret = find_if(v.begin(), v.end(), not1(bind2nd(greater<int>(), 30)));//找出第一个小于等于30
  1. 二元取反
//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);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值