泛型算法本身不会执行容器的操作,它们只会运行于迭代器之上,执行迭代器的操作。因此算法可能改变容器中保存的元素,也可能在容器内移动元素,但永远不会直接添加或删除元素。
只读算法:
accumulate:
1 #include <iostream> 2 #include <algorithm> 3 #include <vector> 4 #include <list> 5 #include <forward_list> 6 #include <deque> 7 #include <string> 8 using namespace std; 9 10 int main(void){ 11 vector<int> v(10, 1); 12 int sum = accumulate(v.cbegin(), v.cend(), 0); 13 cout << sum << endl;//10 14 sum = accumulate(v.cbegin(), v.cend(), 1);//第三个参数是和的初始值且决定了函数中使用哪个加法运算以及返回值的类型 15 cout << sum << endl;//11 16 cout << endl; 17 18 list<string> l = {"fjs", "afjkflf", "wwe"}; 19 string str = accumulate(l.cbegin(), l.cend(), string(""));//注意不能用c风格的字符串,c风格字符串上没有重载+ 20 cout << str << endl;//fjsafjkflfwwe 21 22 deque<double> q(10, 1.1); 23 double cnt = accumulate(q.cbegin(), q.cend(), 0.0);//第三个参数决定了使用何总类型的+ 24 double cc = accumulate(q.cbegin(), q.cend(), 0); 25 cout << cnt << endl;//11 26 cout << cc << endl;//10 27 28 return 0; 29 }
显然,只要支持随机访问(能用迭代器遍历)的容器都支持 accumulate 算法
注意:第三个参数是和的初始值且决定了函数中使用哪个加法运算以及返回值的类型
不能用c风格的字符串,c风格字符串上没有重载+
equal:
1 #include <iostream> 2 #include <algorithm> 3 #include <vector> 4 #include <list> 5 using namespace std; 6 7 int main(void){ 8 vector<string> v(5, "hello"); 9 vector<string> v1(4, "hello"); 10 list<string> l1(5, "hello"); 11 list<const char*> l2 = {"hello", "hello", "hello", "hello", "zzz"}; 12 list<const char*> l3 = {"hello", "hello", "hello", "hello", "zzz"}; 13 14 15 bool flag1 = equal(v.cbegin(), v.cend(), l1.cbegin());//可以两个不同类型的容器之间比较,只要元素之间支持==运算符即可 16 bool flag2 = equal(v.cbegin(), v.cend(), l2.cbegin()); 17 bool flag3 = equal(l2.cbegin(), l2.cend(), l3.cbegin()); 18 // bool flag4 = equal(v.cbegin(), v.cend(), v1.cbegin());//会运行时出错,只接受一个单一的迭代器来表示第二个序列的算法,都假定第二个序列至少与第一个序列一样长 19 cout << flag1 << endl;//1 20 cout << flag2 << endl;//0 21 cout << flag3 << endl;//1 22 23 cout << endl; 24 25 return 0; 26 }
注意:可以两个不同类型的容器之间比较,只要元素之间支持 == 运算符即可
只接受一个单一的迭代器来表示第二个序列的算法,都假定第二个序列至少与第一个序列一样长
写容器元素的算法:
fill/fill_n:
1 #include <iostream> 2 #include <algorithm> 3 #include <vector> 4 using namespace std; 5 6 int main(void){ 7 vector<int> v, v1, v2;//定义三个空容器 8 fill(v.begin(), v.end(), 0); 9 fill_n(v1.begin(), v1.size(), 0); 10 11 // fill_n(v2.begin(), 10, 0);//错误,v2是一个空容器,越界了 12 v2.reserve(5);//给v2分配5个int的空间 13 fill_n(v2.begin(), 5, 0);//v2虽然分配了空间,但其仍然是一个空容器,不改变容器大小无法向其中赋值 14 cout << v2.size() << endl;//0 15 cout << v2.capacity() << endl;//5 16 return 0; 17 }
注意:使用 fill_n 第一个元素传入一个普通迭代器时如果我们第二个参数不传 v.size() 的话很容易导致越界
fill_n 本身不改变容器的大小,若传给 fill_n 的第一个迭代器是一个普通迭代器的话无法给空容器赋值
back_inserter:
1 #include <iostream> 2 #include <iterator> 3 #include <vector> 4 using namespace std; 5 6 int main(void){ 7 vector<int> v1;//空向量 8 auto it = back_inserter(v1); 9 //back_inserter接受一个指向容器的引用,返回一个与该容器绑定的插入迭代器,当我们通过此迭代器赋值时, 10 //赋值运算会调用push_back将一个具有给定值的元素添加到容器中 11 *it = 0;//此时v1中有一个元素0 12 for(const auto indx : v1){ 13 cout << indx << endl; 14 } 15 16 vector<int> v2(4, 1); 17 *back_inserter(v2) = 0; 18 for(const auto indx : v2){ 19 cout << indx << " "; 20 } 21 cout << endl;//1 1 1 1 0 22 23 vector<int> v3; 24 fill_n(back_inserter(v3), 5, 0);//添加10个0到v3中 25 for(const auto indx : v3){ 26 cout << indx << " "; 27 } 28 cout << endl;//0 0 0 0 0 29 return 0; 30 }
注意:back_inserter 接受一个指向容器的引用,返回一个与该容器绑定的插入迭代器,当我们通过此迭代器赋值时,赋值运算会调用 push_back 将一个具有给定值的元素添加到容器中
fill_n 算法本质是对传入的迭代器的操作,所以给 fill_n 传入普通迭代器时不能改变对应容器的大小,若 fill_n 的第一个迭代器参数是插入迭代器时则其可以改变对应容器的大小并插入指定元素
copy:
1 #include <iostream> 2 #include <algorithm> 3 #include <list> 4 #include <deque> 5 #include <vector> 6 using namespace std; 7 8 int main(void){ 9 int a1[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 10 int a2[sizeof(a1) / sizeof(*a1)];//a2与a1的大小一样 11 auto ret = copy(begin(a1), end(a1), begin(a2));//将a1的内容拷贝到a2,返回目标迭代器递增之后的值 12 for(const auto indx : a2){ 13 cout << indx << " "; 14 } 15 cout << endl; 16 cout << (ret == end(a2)) << endl;//1 17 18 list<int> l(5, 1); 19 deque<int> f; 20 copy(l.begin(), l.end(), back_inserter(f)); 21 for(const auto indx : f){ 22 cout << indx << " "; 23 } 24 cout << endl;//1 1 1 1 1 25 26 vector<int> v;//空容器 27 v.reserve(5);//虽然该容器现在被分配了5个int空间,但其仍然是空容器 28 copy(l.begin(), l.end(), back_inserter(v));//向空容器拷入元素,改变了元素大小,必须使用插入迭代器 29 cout << v.size() << endl;//5 30 cout << v.capacity() << endl;//5 31 for(const auto indx : v){ 32 cout << indx << " "; 33 } 34 cout << endl; 35 36 vector<int> v1(5);//一个含有5个元素的容器 37 copy(l.begin(), l.end(), v1.begin());//只是替换原有元素,不需要用插入迭代器 38 for(const auto indx : v1){ 39 cout << indx << " "; 40 } 41 cout << endl;//1 1 1 1 1 42 return 0; 43 }
注意:越界问题
对于要改变容器大小的地方不能用普通迭代器
replace/replace_copy
1 #include <iostream> 2 #include <algorithm> 3 #include <forward_list> 4 #include <vector> 5 using namespace std; 6 7 int main(void){ 8 forward_list<int> f(10, 0); 9 replace(f.begin(), f.end(), 0, 1024);//将f中所有0替换成1024 10 for(const auto indx : f){ 11 cout << indx << " "; 12 } 13 cout << endl << endl; 14 15 forward_list<int> l(10, 0); 16 vector<int> v; 17 replace_copy(l.cbegin(), l.cend(), back_inserter(v), 0, 42);//将l拷贝到v并将v中元素值为0的修改成42 18 for(const auto indx : l){ 19 cout << indx << " "; 20 } 21 cout << endl; 22 for(const auto indx : v){ 23 cout << indx << " "; 24 } 25 cout << endl; 26 27 return 0; 28 }
注意:对于要改变容器大小的地方不能用普通迭代器,如:本例中 replace_copy 中因为 v 是个空迭代器,若以第三个参数必须用插入迭代器
重排容器元素的算法:
unique:
1 #include <iostream> 2 #include <algorithm> 3 #include <vector> 4 using namespace std; 5 6 void work(vector<string> &words){ 7 sort(words.begin(), words.end());//unique只剔除相邻的相同元素 8 auto end_unique = unique(words.begin(), words.end());//将相邻的相同的元素"删除",返回一个指向不重复值范围末尾的迭代器 9 words.erase(end_unique, words.end());//上面的"删除"并不是真的删除,只是覆盖了而已,我们通过erase真正的将其删除 10 } 11 12 int main(void){ 13 vector<string> v = {"ac", "ab", "ac", "a", "a"}; 14 work(v); 15 for(const auto indx : v){ 16 cout << indx << " "; 17 } 18 cout << endl;//a ab ac 19 20 return 0; 21 }
注意:unique 只剔除相邻的相同元素
将相邻的相同的元素 "删除",返回一个指向不重复值范围末尾的迭代器。但其不真正的删除元素,只是将重复的值移到迭代器末尾而已,也可能会将其覆盖
谓词:
谓词是一个可调用的表达式,其返回结果是一个能用作条件的值。标准库算法所使用的谓词分两类:一元谓词(意味着它们只接受单一参数) 和二元谓词(意味着它们有两个参数)。接受谓词参数的算法对输入序列中的元素调用谓词。因此,元素类型必须能转换为谓词参数类型。如:sort 能接受一个二元谓词参数,这个谓词用来代替 < 来比较元素
sort 和 stable_sort:
sort 和 stable_sort 的使用规则完全一样,有区别的是带有 stable 的是稳定排序~
partition 和 stable_partition:
1 #include <iostream> 2 #include <algorithm> 3 #include <vector> 4 using namespace std; 5 6 bool is_longer_than_5(const string &s){ 7 return s.size() >= 5; 8 } 9 10 int main(void){ 11 vector<string> v1 = {"fjskf", "fjslfjksl", "fjsklfk", "f", "fdds", "fjs", "fjslf"}; 12 vector<string> v2 = {"fjskf", "fjslfjksl", "fjsklfk", "f", "fdds", "fjs", "fjslf"}; 13 14 auto pos1 = partition(v1.begin(), v1.end(), is_longer_than_5);//该算法是非稳定的 15 auto pos2 = stable_partition(v2.begin(), v2.end(), is_longer_than_5);//该算法是稳定的 16 17 for(auto it = v1.begin(); it != pos1; it++){ 18 cout << *it << " "; 19 } 20 cout << endl; 21 22 for(auto it = v2.begin(); it != pos2; it++){ 23 cout << *it << " "; 24 } 25 cout << endl; 26 27 return 0; 28 }