大多数算法定义在头文件algorithm中, 在头文件numeric中定义了一组数值泛型算法(如equal)。
只读算法
find
find(vec.begin(),vec.end(),val);
查找val的值,返回指向 第一个值等于val的 元素 的迭代器。
accumulate (定义在numeric)
accumulate(vec.begin(),vec.end(),0);
- 初始值为0,将vec中各元素相加。
- 第三个参数类型决定了使用哪个加法运算符 以及返回值的类型
- eg:
string sum=accumulate(v.cbegin(),c.cend(),string(""));
- ↑ string串相加。
字符串字面值 “ ”,的类型是 const char* ,是一个常量,所以不能进行加减操作。
- equal
equal(roster1.cbegin(),roster1.cend(),roster2.cbegin())
- 依次比较两个序列的值。
- 因为第二个序列的迭代器只接收了首元素,所以要求第二个序列至少要和第一个序列一样长。
写容器的算法
- fill
fill(vec.begin(),vec.end(),0);
- 将0写入vec中每个元素。
- 只要传输的是一个有效的范围,写操作就是安全的。
fill_n(iter,n,val);
// 向iter后的n个元素写入val
- 会出现越界问题。
- 为了解决越界问题 采取的方法是 使用插入迭代器
- copy
copy(vec.begin(),vec.end(),mubiao.begin());
replace(vec.begin(),vec.end(),目标元素,替换的元素);
- 会改变原序列
replace_copy(vec.begin(),vec.end(),插入迭代器,目标元素,替换的元素);
- 之后通过插入迭代器生成了新的序列,原序列不变。
排序算法
- sort (按首字母字典序排列)
sort(vec.begin(),vec.end());
sort(vec.begin(),vec.end(),[](const string& str_1,const string& str_2){return str_1.size()>str_2.size()})
- 重载形式可以接受一个二元谓词
- unique
auto end_unique=unique(vec.begin(),vec,end());
- 去重(将重复元素移动到末尾)。并返回不重复范围末尾的迭代器。
- unique就是让连续的相同值变成一个 (所以一般要配合sort使用)
- stable_sort (按长度排序,并且相同长度维持字典序)
- 使相同长度的元素按字典序排列。
- 接受一个二元谓词。
stable_sort和sort的区别
- stable_sort的用法与sort一致,区别是stable_sort函数遇到两个数相等时,不对其交换顺序;这个应用在数组里面不受影响,当函数参数传入的是结构体时,会发现两者之间的明显区别
查找
- find_if
auto wc=find_if(vec.begin(),vec.end(),isPrimer);
- 查找序列中第一个满足isPrimer的对象(isPrimer是一个可调用对象)。并返回一个指向他的迭代器。
- 接受一个一元谓词。
- for_each
for_each(vec.begin(),vec.end(),func);
- func是一个可调用对象,for_each对序列中所有对象执行func。
- 接受一个一元谓词。
lambda (C++11)
aufo f=[capture list](parameter list) ->int {return 1;};
lambda是一个可调用对象 f(args); args是一个以逗号为分割的参数列表。
捕获方式
值捕获
就是普通的捕获…可以捕获多个值
- 在定义时捕获
如果想通过捕获的变量改变原来的变量…
auto f=[vi]()mutable{return ++vi;};
引用捕获
对于无法进行拷贝的对象,如 ostream,
for_each(words.begin(),words.end(),[&os,c](const string &s){os<<s<<c;});
当然也可以对于普通的变量进行引用捕获,但影响是只有在调用lambda语句时才进行捕获,如果在之前改变了所引对象的值,捕获的值也会变化。
隐式捕获
= 值捕获, & 引用捕获。
- [&,c] means: 变量c使用值捕获,其他使用引用捕获
- [=, &c] : 变量c使用引用捕获,其他使用值捕获。
返回类型
lambda只能单一返回。 如果出现两个return 则会默认返回类型是void。 所以在这种情况下要人为规定返回类型。
在parameter list之后, function body之前使用,
-> int
参数绑定
- 使用bind语句,可以实现类似lambda的功能,也可以用于更改形参顺序等。
- 对于lambda 如果要在多处使用,需要多次定义。所以如果要多处使用相同的lambda操作,需要一个函数来代替。
- …….以后再看 太繁琐了,,
插入迭代器
back_inserter
接收一个参数。为要插入的对象front_inserter
接受一个参数。同上inserter
接收两个参数,一个是要插入的对象,另一个是指向给定容器位置的迭代器, 元素会被插入到迭代器所指位置之前。
流迭代器
istream_iterator
ostream_iterator
反向迭代器
reverse_iterator
- 使用
vec.rbegin(), vec.rend()
作为迭代器,分别指向尾元素(最后一个元素之后)的前一个元素 ,首元素的前一个元素(什么都没有) - 反向迭代器: 右闭合区间
(vec.crend(),vec.crbegin()]
- ↑ 是按元素顺序写的,实际使用反向迭代器时,还是crbegin在前,crend在后。(不然也不能反向了233)。
- 正向迭代器: 左闭合区间 [vec.begin(),vec.end() )
- 有一个成员函数 base(), 可以把向左移动的迭代器转为向右移动的迭代器, 向右时,迭代器指向的元素为原来向左时指向元素的右边那个。
- 使用
泛型算法结构(分类方式)
- 根据算法本身功能分类
- 根据只读 ,只写 ,重新排序 分类。
- 根据可以使用的迭代器操作分类。
- 输入迭代器
- 只读不写,单遍扫描,只能递增。支持判定运算符(== , !=) 、解引用(*)(只能出现在赋值运算右侧)、箭头运算符(->)
- 输出迭代器
- 只写不读,单遍扫描,只能递增,支持解引用(*)()只能出现在赋值号左侧。
- 前向迭代器
- 支持上述所有操作+多遍扫描,只能递增。
- 双向迭代器 (如list的迭代器)
- 支持上述所有操作+多遍扫描+可递增也可递减
- 随机访问迭代器 (vector的迭代器)
- 支持所有操作+比较两个迭代器相对位置的关系运算符(> , < , <=, >=)+ 迭代器和一个整数值的加减运算(+, +=, - ,-=) + 两个迭代器的减法运算符 (-)。
算法命名规则
_if
_copy
特定容器算法
链表的splice算法
#include <iostream> #include <list> #include <string> #include <algorithm> using namespace std; int main () { list<int> mylist1, mylist2; list<int>::iterator it; // set some initial values: for (int i=1; i<=4; i++) mylist1.push_back(i); // mylist1: 1 2 3 4 for (int i=1; i<=3; i++) mylist2.push_back(i*10); // mylist2: 10 20 30 it = mylist1.begin(); ++it; // points to 2 mylist1.splice (it, mylist2); // mylist1: 1 10 20 30 2 3 4 // mylist2 (empty) // "it" still points to 2 (the 5th element) mylist2.splice (mylist2.begin(),mylist1, it); // mylist1: 1 10 20 30 3 4 // mylist2: 2 // "it" is now invalid. it = mylist1.begin(); advance(it,3); // "it" points now to 30 mylist1.splice ( mylist1.begin(), mylist1, it, mylist1.end()); // mylist1: 30 3 4 1 10 20 cout << "mylist1 contains:"; for (it=mylist1.begin(); it!=mylist1.end(); it++) cout << " " << *it; cout << "/nmylist2 contains:"; for (it=mylist2.begin(); it!=mylist2.end(); it++) cout << " " << *it; cout << endl; list<string> dictionary, bword; dictionary.push_back("any"); dictionary.push_back("angle"); dictionary.push_back("ajust"); dictionary.push_back("common"); dictionary.push_back("cannon"); dictionary.push_back("company"); bword.push_back("blue"); bword.push_back("banana"); bword.push_back("break"); list<string>::iterator its = dictionary.begin(); for (int i = 0; i < 3; i++) its++; dictionary.splice(its, bword); copy(bword.begin(), bword.end(), ostream_iterator<string>(cout, "/n")); return 0; }