文章目录
本文适合新手阅读,亦可所谓手册查阅
前言
泛型算法与容器无关。操作迭代器。
算法不会执行容器操作,算法本身并不改变容器大小,但是可以通过操纵insert, erase来改变容器。
泛型算法
只读
accumulate(c.begin(), c.end(), 初始加和数) | |
equal(c.cbegin(), c.edn(), c2.cbegin()) |
写容器
fill(c.begin(), c.end(), 0); //将每个元素置为0
fill(c.begin(), c.begin()+c.size()/2, 10); //将容器的一个子序列设置为10
fill_n(dest, n, val);
back_inserter
有点像.push_back(val)
返回容器最后位置的迭代器
vector<int> vec;
fill_n(back_inserter(vec), 10, 0); //添加10个元素0到vec
拷贝算法
int a1[] = {0,1,2,3,4,5,6,7,8,9};
int a2[sizeof(a1) / sizeof(*a1)]; //a2与a1大小一样
auto res = std::copy(begin(a1), end(a1), a2);//返回a2拷贝赋值后的最后一个元素的后一位
//copy(开始位置,结束位置, 目的序列的起始位置)
//将[ )中的值所有0,替换为42
replace(ilst.begin(), ilst.end(), 0, 42);
replace_copy(ilst.begin(), ilst.end(), back_inserter(ivec), 0, 42);
排序
sort(迭代器1, 迭代器2) //完成sort后,容器有序
unique(迭代器1, 迭代器2)//重排范围,“消除”重复项,返回不重复范围最后位置的迭代器
标准库算法对迭代器而不是容器进行操作。因此,算法不能(直接)添加或删除元素。
void elimDups(vector<string> &words){
sort(words.begin(), words.end());
auto end_unique = unique(words.begin(), words.end());
words.erase(end_unique, words.end());
}
定制操作
bool isShorter(const string &s1, const string &s2){
return s1.size() < s2.size();
}
sort(words.begin(), words.end(), isShorter);
stable_sort(words.begin(), words.end(), isShorter);
partition(vec.begin(), vec.end(), isShorter);
lambda表达式
可将其理解为一个未命名的内联函数,可以定义在函数内部。
[ capture list ] ( parameter list ) -> return type { function body }
capture list (捕获列表)在lambda所在函数中定义的局部变量的列表(通常为空),捕获列表只用于局部非static变量,lambda可以直接使用局部static变量和在它所在函数之外声名的名字。
auto f = []{return 42;} ; // ()->return type 和省略
cout << f() << endl; //print 42
必须使用位置返回。不能有默认参数。
find_if
auto wc = find_if(words.begin(), words.end(),
[sz](const string &a){return a.size() >= sz;} );
auto count = words.end() - wc;
void biggies(vector<string>& words, vector<string>::size_type sz){
elimDups(words); //将words按字典顺序排序,删除重复单词
//按长度排序,长度相同的单词维持字典
stable_sort(words.begin(), words.end(),
[](const string &a, const string &b){return a.size()<b.size();} );
auto wc = find_if(words.begin(), words.end(),
[sz](const string &a){return a.size()>=sz; });
auto count = words.end() - wc;
cout << count << " " << make_plural(count, "word", "s") << " of length "
<< sz << " or longer " << endl;
for_each(wc, words.end(), [](const string &s){cout << s << " ";} );
cout << endl;
}
lambda捕获和返回
值捕获的前提是变量可以拷贝。
// 值捕获
void fcn1(){
auto v1 = 42;
auto f = [v1]{return v1;};
v1 = 0;
auto j = f(); //j为42,f保存了我们创建它时v1的拷贝
}
//引用捕获
void fcn1(){
auto v1 = 42;
auto f = [&v1]{return v1;};
v1 = 0;
auto j = f(); //j为0,f保存了v1的引用,而非拷贝
}
//隐式捕获
wc = find_if(words.begin(), sords.end(),
[=]/*隐式值捕获*/(const string&s){return s.size()>=sz;} );
[&]/*隐式引用捕获*/(const string&s){return s.size()>=sz;}
//只有这两种写法
[&, c]{os << s << c;} //
[=, &os]{os <<s<<c ;} //
可变lambda
void fcn3(){
int v1 = 42;
auto f = [v1]() mutable {return ++v1;};
v1 = 0;
auto j = f(); //j == 43
}
transform(vi.begin(), vi.end(), vi.begin()/*目的位置*/,
[](int i){return i < 0 ? -i : i;} ); // 正确lambda只有一条return语句,默认推断正确
[](int i){if(i<0)return -i;else return i;} // 错误,有多条语句默认推断void与实际不符
[](int i)->int{return i < 0 ? -i : i;} // 正确
auto i = count_if(迭代器范围a, 迭代器范围b,谓词);//对输入范围中每个元素执行谓词操作,返回一个计数值,表示谓词有多少次为真。
int main(){
int ival = 9;
while (ival){
[&ival]()->bool{if (ival>0) return ival-- == 0; }();
cout << ival << " ";
}
return 0;}
参数绑定
bind定义在头文件 functional 中
auto newCallable = std::bind(callabel, arg_list);
placeholders
placeholders命名空间也也定义在头文静 functional 中
bool check_size(const string &s, string::size_type sz){
return s.size() >= sz;
}
auto wc = std::find_if(words.begin(), words.end(),
std::bind(check_size, std::placeholders::_1) );
using namesapce namespace_name;
using namespace std::placeholders;
auto g = std::bind(f, a, b, _2, c, _1);
//等价于
g(_1, _2) 映射为 f(a, b, _2, c, _1)
//如:
g(X, Y) 会调用 f(a, b, Y, c, X)
auto isShorter(const string&a, const string&b) -> bool{
return a.size() < b.size();
}
bind(isShorter, _2, _1);
以引用的方式传递参数
ref 和 cref 标准库函数均定义在头文件 functional 中
std::for_each(words.begin(), words.end(), bind(print, std::ref(os), _1, ' ') );
迭代器
头文件 iterator
- 插入迭代器 insert iterator
- 流迭代器 stream iterator
- 反向迭代器 reverse iterator
- 移动迭代器 move iterator
插入迭代器
有点类似Python中的生成器,每次使用后,下次再使用输出改变
back_inserter : 调用 push_back()
front_inserter : 调用push_front
inserter : 调用insert
//若it是由inserter生成的迭代器
*it = val;
//equivalent
it = c.insert(it, val); //it指向新插入的元素
++ it ; //递增it使它指向原来的元素
list<int> lst1={1,2,3,4}, lst2, lst3;
//lst2 4,3,2,1
copy(lst.cbegin(), lst.cend(), front_inserter(lst2) );
//lst3 1,2,3,4
copy(lst.cbegin(), lst.cend(), inserter(lst3, lst3.begin() ) );
iostream迭代器
pass
反向迭代器
pass
泛型算法结构
泛型算法要求的迭代器操作可以分为5个迭代器类别
输入迭代器 input iterator:可以读取序列中的元素。它必须支持:
- == !=
- ++
- 解引用(*), 解引用只会出现在赋值运算符的右侧
- -> equivalent to (*it).member
**输出迭代器 output iterator ** :只写而不读元素。它必须支持:
- ++
- *, 只出现在赋值运算符的左侧
**前向迭代器 forward iterator ** :可读写元素。
**双向迭代器 forward iterator ** :可读写元素。
**随机访问迭代器 random-access iterator ** :可读写元素。支持:
- < <= > >=
- += + - -=
- 迭代器之间的减法运算
- 下标运算符(iter[n]), 与*(iter[n])等价
算法形参模式
**alg ( ** beg, end, other args );
**alg ( ** beg, end, dest, other args );
**alg ( ** beg, end, beg2, other args );
**alg ( ** beg, end, beg2, end2, other args );
算法命名规范
函数层重载
unique(beg, end); //使用 == 运算符比较元素
unique(beg, end, comp); //使用谓词comp比较元素
_if 版本
find(beg, end, val); //找查输入范围中val第一次出现的位置
find_if(beg, end , pred); //找查令第一个pred(函数)为真的元素
replace(beg, end, odd_val, new_val);
replace_if(beg, end, pred, new_val);
区分拷贝元素的版本和不拷贝的版本 _copy
reverse(beg, end); //反转输入范围中元素的顺序
reverse_copy(beg, end, dest); //将元素按逆序拷贝到dest
//_copy + _if version
// remove odd from v1
remove_if(v1.begin(), v1.end(), [](int i){return i % 2;});
//copy even from v1 to v2 without changed v1
//首先从v1拷贝到v2,然后判断v2中的元素是否移除
remove_copy_if(v1.begin(), v1.end(), back_inserter(v2),
[](int i){return i % 2;});
replace_copy(beg, end, dest, old_val, new_val);
replace_copy_if(beg, end, dest, pred, new_val);
特定容器算法
对于list和forward_list,应该优先使用成员函数版本的算法,而不是通用算法
splice成员
总结
标准库定义了大约100个类型无关的对序列进行操作的算法。
五类迭代器:输入(读取)、输出(写入)、前向、双向及随机访问迭代器。
一元谓词,二元谓词