10.2、初識泛型算法
1、只讀算法
//對vec中的元素求和,和的初值是0,頭文件是numeric
int sum = accumulate(vec.cbegin(), vec.cend(), 0);
//將vector中所有的string元素連接起來
string sum = accumulate(v.cbegin(), v.cend(), string(""));
//equal用於確定兩個序列是否保存相同的值,第二個序列元素數目至少應該與第一個一樣多
equal(roster1.cbegin(), roster1.cend(), roster2.cbegin());
2、寫容器元素的算法
//將每個元素重置爲0
fill(vec.begin(), vec.end(), 0);
vector<int> vec;
fill_n(vec.begin(), vec.size(), 0);//將所有元素重置爲0,不可指定大小,算法不檢查寫操作
fill_n(back_inserter(vec), 10, 0); //添加10個元素到vec
back_inserter接受一個指向容器的引用,返回一個與該容器綁定的插入迭代器。頭文件iterator
int a1[] = {0,1,2,3,4,5,6,7,8,9};
int a2[sizeof(a1)/sizeof(*a1)]; //a2與a1大小一樣
//ret指向拷貝到a2的尾元素之後的位置
auto ret = copy(begin(a1), end(a2), a2); //把a1的內容拷貝給a2
//將所有值爲0的元素改爲42
replace(ilist.begin(), ilist.end(), 0, 42);
//使用back_inserter按需要增長目標序列
replace_copy(ilist.cegin(), ilist.cend(), back_inserter(ivec), 0, 42);
//此調用後,ilist並未改變,ivec包含ilist的一份拷貝,不過原來在ilist中值爲0的元素改爲42
3、重排容器元素的算法
//練習10.9
#include<iostream>
#include<fstream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
inline void output_words(vector<string> &words) //輸出
{
for(auto iter = words.begin(); iter != words.end(); iter++)
cout << *iter << " ";
cout << endl;
}
void elimDups(vector<string> &words)
{
output_words(words);
sort(words.begin(), words.end()); //按字典序排序,以便查找重複單詞
output_words(words);
//unique重排輸入範圍,使得每個單詞只出現一次
//排列在範圍前部,返回指向不重複區域之後一個位置的迭代器
auto end_unique = unique(words.begin(), words.end());
output_words(words);
//使用向量操作erase刪除重複單詞
words.erase(end_unique, words.end());
output_words(words);
}
int main(int argc, char *argv[])
{
ifstream in(argv[1]);
if(!in){
cout << "打開輸入文件失敗!" << endl;
exit(1);
}
vector<string> words;
string word;
while(in >> word)
words.push_back(word);
elimDups(words);
return 0;
}
10.3 定製操作
1、向算法傳遞函數
stable_sort 穩定排序算法,可以維持相等元素的原有順序。
//練習10.13
#include<iostream>
#include<fstream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
inline void output_words(vector<string>::iterator beg, vector<string>::iterator end) //輸出
{
for(auto iter = beg; iter != end; iter++)
cout << *iter << " ";
cout << endl;
}
bool five_or_more(const string &s1) //找出大於5的string,返回true
{
return s1.size() >= 5;
}
int main(int argc, char *argv[])
{
ifstream in(argv[1]);
if(!in){
cout << "打開輸入文件失敗!" << endl;
exit(1);
}
vector<string> words;
string word;
while(in >> word)
words.push_back(word);
output_words(words.begin(), words.end());
//partition接受一個謂詞,對容器內容進行劃分,true排在容器的前半部分,false排在後半部分
auto iter = partition(words.begin(), words.end(), five_or_more);
output_words(words.begin(), words.end());
return 0;
}
2、lambda表達式
可調用對象,函數、函數指針、重載了函數調用運算符的類、lambda表達式。
一個lambda表達式表示一個可調用的代碼單元,可理解爲一個未命名的內聯函數。
[capture list] (parameter list) -> return type {function body}
參數列表和返回類型可忽略,必須包含捕獲列表(一個lambda所在函數中定義的局部變量的列表)和函數體。
//第三個參數爲lambda表達式,實現isShorter的功能
stable_sort(words.begin(), words.end(), [](const string &a, const string &b)
{ return a.size() < b.size();});
上面空的捕獲列表表明此lambda表達式不使用它所在函數中的任何局部變量。
//練習10.16
#include<iostream>
#include<fstream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
inline void output_words(vector<string> &words) //輸出
{
for(auto iter = words.begin(); iter != words.end(); iter++)
cout << *iter << " ";
cout << endl;
}
void elimDups(vector<string> &words)
{
sort(words.begin(), words.end()); //按字典序排序,以便查找重複單詞
output_words(words);
//unique重排輸入範圍,使得每個單詞只出現一次
//排列在範圍前部,返回指向不重複區域之後一個位置的迭代器
auto end_unique = unique(words.begin(), words.end());
//使用向量操作erase刪除重複單詞
words.erase(end_unique, words.end());
}
string make_plural(size_t ctr, const string &word, const string &ending)
{
return (ctr > 1) ? word + ending : word;
}
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(); });
//獲取一個迭代器,指向第一個滿足size() >= sz的元素
auto wc = find_if(words.begin(), words.end(), [sz](const string &a)
{ return a.size() >= sz; });
//計算滿足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;
}
int main(int argc, char *argv[])
{
ifstream in(argv[1]);
if(!in){
cout << "打開輸入文件失敗!" << endl;
exit(1);
}
vector<string> words;
string word;
while(in >> word)
words.push_back(word);
biggies(words, 4);
return 0;
}
3、lambda捕獲和返回
值捕獲:與參數不同,被捕獲的變量的值是在lambda創建時拷貝,而不是調用時拷貝。
引用捕獲:當以引用方式捕獲一個變量時,必須保證在lambda執行時變量是存在的。
隱式捕獲:&隱式引用捕獲,=隱式值捕獲,顯式捕獲可以和隱式捕獲混合使用
可變lambda:值捕獲的方式可以加mutable改變值,引用捕獲取決於是否const
指定lambda返回類型:使用尾置返回類型
4、參數綁定
標準庫bind函數: auto newCallable = bind(callable, arg_list) newCallable本身是一個可調用對象,arg_list是一個逗號分隔的參數列表,對應給定的callable的參數。 arg_list參數可能包含形如_n的名字,n爲整數,這些參數是“佔位符”。數值n表示生成的可調用對象中參數的位置。頭文件 functional。
//練習10.22
#include<iostream>
#include<fstream>
#include<vector>
#include<string>
#include<algorithm>
#include<functional>
using namespace std;
using namespace std::placeholders;
inline void output_words(vector<string> &words) //輸出
{
for(auto iter = words.begin(); iter != words.end(); iter++)
cout << *iter << " ";
cout << endl;
}
bool check_size(const string &s, string::size_type sz)
{
return s.size() >= sz;
}
string make_plural(size_t ctr, const string &word, const string &ending)
{
return (ctr > 1) ? word + ending : word;
}
void biggies(vector<string> &words, vector<string>::size_type sz)
{
output_words(words);
//計算滿足size >= sz的元素的數目
//count_if:接受一對迭代器,和一個謂詞,返回一個計數值,表示謂詞有多少次爲真。
auto bc = count_if(words.begin(), words.end(), bind(check_size, _1, sz));
cout << bc << " " << make_plural(bc, "word", "s")
<< " of length " << sz << " or longer" << endl;
}
int main(int argc, char *argv[])
{
ifstream in(argv[1]);
if(!in){
cout << "打開輸入文件失敗!" << endl;
exit(1);
}
vector<string> words;
string word;
while(in >> word)
words.push_back(word);
biggies(words, 6);
return 0;
}
10.4、再探迭代器
1、插入迭代器
back_inserter front_inserter inserter
2、iostream迭代器
3、反向迭代器
流迭代器和forward_list不支持創建反向迭代器。
//10.37給定一個包含10個元素的vector,將位置3到7之間的元素按逆序拷貝到一個list中
#include<iostream>
#include<vector>
#include<algorithm>
#include<list>
#include<iterator>
using namespace std;
int main()
{
vector<int> vi = {0,1,2,3,4,5,6,7,8,9};
ostream_iterator<int> out_iter(cout, " ");
copy(vi.cbegin(), vi.cend(), out_iter);
cout << endl;
list<int> li;
vector<int>::reverse_iterator re(vi.begin() + 2);
vector<int>::reverse_iterator rb(vi.begin() + 7);
copy(rb, re, back_inserter(li));
copy(li.begin(), li.end(), out_iter);
cout << endl;
return 0;
}
10.5、泛型算法結構
1、5類迭代器
2、算法形參模式
10.6、特定容器算法