C++ algorithm算法库
C++ algorithm算法库Xun 标准模板库(STL)中定义了很多的常用算法,这些算法主要定义在
下面的内容主要来源于《C++ Primer》第5版的附录A2,这里主要是添加了一些示例程序。 各个算法用到的主要参数有:
此外,部分算法要求序列是有序的,默认是使用小于运算符( 查找对象的算法这些算法在一个输入序列中搜索一个指定值或是一个序列。 不接受谓词的版本使用底层相等运算符( 简单查找算法
std::vector<int> v{ -2,-1,1,2 }; std::vector<int>::iterator iter = find(v.begin(),v.end(),5);//没找到,iter==v.end() if (iter == v.end()) std::cout << "oops"; long long n = std::count_if(v.begin(),[](int val) {return val > 0; });//正数个数为2
这些算法都返回 std::string s("123abc"); std::cout << std::all_of(s.begin(),s.end(),[](char c) {return isalpha(c); });//输出0,不全为字母 查找重复值的算法
返回一个迭代器指向第一对相邻重复元素的迭代器,若无相邻元素则返回 std::vector<int> v{ 5,2,3,6,10 }; std::vector<int>::iterator iter1 = std::adjacent_find(v.begin(),v.end());//iter1指向第一个2 std::cout << *(iter1+1); auto iter2 = std::adjacent_find(v.begin(),[](int a,int b) {return b == 2 * a; });//查找下一个元素是上一个元素二倍的位置,iter2指向3
在序列中查找 struct A { int i; char c; }; std::vector<A> vA{ {1,'v'},{2,'c'},{3,'d'},'k'},'o'},{5,'l'} }; auto iter = std::search_n(vA.begin(),vA.end(),A{ 3,'x' },//查找与A{3,'x'}相等的连续3个元素出现的位置 [](A a,A b)//定义类型A的相等为成员变量i相等 {return a.i == b.i; });//iter指向{3,'d'} 查找子序列的算法
返回一个迭代器指向第二个序列在第一个序列中第一次出现的位置,若未找到则返回 std::vector<int> v{ 1,4,12,5,11 }; int array[3] = { 2,3 }; auto iter1 = std::search(v.begin(),std::begin(array),std::end(array));//在v中查找子序列array,没找到,iter1指向v的尾后 auto iter2 = std::search(v.begin(),std::end(array),int b) //在v中查找连续的3个数,分别能被2,2,3整除 {return a % b == 0; });//iter2指向4
返回一个迭代器指向第二个序列中任意一个元素在第一个序列中首次出现的位置,若未找到则返回 std::vector<int> v{ 1,11 }; int array[3] = { 5,3 }; auto iter1 = std::find_first_of(v.begin(),array,array + 3);//array中的元素第一个在v中出现的是3,iter1指向v中的3 auto iter2 = std::find_first_of(v.begin(),array + 3,int b)//在v中查找第一个与array中元素相加等于10的元素(即寻找5,6,7) {return a + b == 10; });//iter2指向6,6+4==10
类似 std::vector<int> v{ 1,7,8,9 }; int array[3] = { 1,3 }; std::forward_list<int> lst{ 9,7 }; auto iter1 = std::find_end(v.begin(),array + 3);//iter1指向v中第二个(最后一个){1,2,3}的首位置元素1 auto iter2 = std::find_end(v.begin(),lst.begin(),lst.end());//没找到,iter2指向v的尾后 其他只读算法
对序列中的每个元素应用可调用对象 std::vector<int> v{ 1,5 }; std::for_each(v.begin(),[](int& a) {a *= 2; });//传入引用,将v中的每个元素修改为自身的2倍 for (int& i : v)//范围for循环,使用引用同样可以修改元素 {//若只有一条语句则可以省略花括号 std::cout << i << ' '; }
返回一个迭代器的 std::vector<int> v1{ 1,3 }; std::vector<int> v2{ 1,5 };//v2的长度需不小于v1的长度 std::pair<std::vector<int>::iterator,std::vector<int>::iterator>//一般用auto iters1 = std::mismatch(v1.begin(),v1.end(),v2.begin());//iters1.first指向v1中的3,iters1.second指向v2中的4 auto iters2 = std::mismatch(v1.begin(),v2.begin(),//没找到不匹配的元素对 [](int a,int b)//iters2.first指向v1的尾后,iters2.second指向v2中的5 {return abs(a - b) < 2; });//定义匹配为两元素之差的绝对值小于2
确定两个序列是否相等,返回一个 std::vector<int> v1{ 1,5 }; bool b = std::equal(v1.begin(),//相等返回true,只检查前v1.size()个元素 [](int a,int b) {return abs(a - b) < 2; });//定义相等为两元素之差的绝对值小于2 二分搜索算法这些算法要求序列是有序的,算法默认使用小于运算符进行比较,若使用谓词,则对小于进行重新定义。
返回一个 std::vector<int> v1{ 10,9,1 }; std::vector<int> v2{ 1,10 }; bool b1 = std::binary_search(v1.begin(),6);//b1==false,v1不是升序使得搜索方向错误 bool b2 = std::binary_search(v2.begin(),v2.end(),6);//b2==true struct A { int i; char c; }; std::vector<A> vA{ {1,{4,{6,'l'} };//按i升序 bool b3 = std::binary_search(vA.begin(),'h' },//返回true [](A a,A b) {return a.i < b.i; });//重定义A的小于为成员变量i的小于
std::vector<double>v{ 1,6 };//升序 auto iter1 = std::lower_bound(v.begin(),4.0);//iter1指向第一个不小于4.0的值,v中第一个4 auto iter2 = std::upper_bound(v.begin(),4.5);//iter2指向第一个大于4.5的值,v中最后一个4后的5 auto iters = std::equal_range(v.begin(),4.0);//first指向第一个4,second指向5 写容器元素的算法只写不读元素的算法
给序列中每个元素赋一个新值。 std::vector<int>v(6,-2);//v中存了6个-2 std::fill_n(v.begin(),5);//v的前3个元素被改写为5 std::fill(v.begin() + 3,10);//v[3]及之后的元素被改写为10 std::fill_n(std::back_inserter(v),15);//在v的末尾再添加3个15 std::default_random_engine e(static_cast<unsigned>(time(0)));//随机数生成器 std::uniform_int_distribution<int> u1(0,10);//生成[0,10]的随机数 std::uniform_int_distribution<int> u2(11,20);//生成[11,20]的随机数 std::generate_n(v.begin(),[&]() {return u1(e); });//将v的前5个数改写为[0,10]的随机数 std::generate(v.begin() + 5,[&]() {return u2(e); });//将v[5]及之后的元素改写为[11,20]的随机数 使用输入迭代器的写算法
将输入范围内的元素复制到目的序列, int array1[5] = { 1,5 }; int array2[5]; std::copy(std::begin(array1),std::end(array1),std::begin(array2));//数组不允许直接复制 std::vector<int>v; v.reserve(5); std::copy_if(std::begin(array1),std::back_inserter(v),[](int a) {return a & 1; });//只复制奇数,v={1,5} std::copy_n(array1 + 1,v.begin());//v之前有3个元素,不会越界,现在v={2,5}
对输入序列中的每个元素调用 std::vector<int>v(5);//v中有5个元素 {//一个新的生存区 std::vector<int>temp{ 1,5 }; std::move(temp.begin(),temp.end(),v.begin()); }//生存区结束
对输入序列中的元素进行变换,结果写入目的序列,输入序列不作改变。 std::vector<int>v1{ 1,5 }; std::vector<int>v2{ 5,1 }; std::vector<int>v3; std::vector<int>v4; std::transform(v1.begin(),std::back_inserter(v3),[](int a) {return a * 2; });//将v1中元素值的2倍写入v3 std::transform(v1.begin(),std::back_inserter(v4),int b) {return a * b; });//v4中元素为v1与v2中对应元素的乘积
将序列中满足条件的元素替换为新值写入到目的序列中,输入序列不作改变。 std::vector<int>v1{ 1,5 }; std::vector<int>v2(v1.size()); std::vector<int>v3(v1.size()); std::replace_copy(v1.begin(),333);//将v1中的3替换为333后写入v2,v2={1,333,5} std::replace_copy_if(v1.begin(),v3.begin(),//v3={-1,5} [](int a) {return a < 3; },-1);//将v1中小于3的元素替换为-1写入v3
将两个有序序列合并为一个有序序列写入 std::vector<int> v1{ 1,9 };//升序 std::vector<int> v2{ 2,10 };//升序 std::vector<int>v3; v3.reserve(v1.size() + v2.size()); std::merge(v1.begin(),std::back_inserter(v3));//v3=[1-10] 使用前向迭代器的写算法这些算法会向输入序列写入元素
std::vector<int> v1{ 1,9 }; std::vector<int> v2{ 2,10 }; std::iter_swap(v1.begin(),v1.begin() + 1);//交换v1的前两个元素,v1={3,9} std::swap_ranges(v2.begin(),v2.begin() + 2,v2.begin() + 3);//将v2的前2个元素与从v2[3]开始的2个元素进行位置交换,v2={8,10,4}
使用新值替换每个匹配元素。 //将v中的非0元素置0,0元素置1 std::vector<int> v{ -2,2 }; std::replace(v.begin(),2);//将v中的1改写为2 std::replace_if(v.begin(),[](int a) {return !a; },1);//将v中的0改写为1 std::replace_if(v.begin(),[](int a) {return a != 1; },0);//将v中的非0值改写为0 使用双向迭代器的写算法
将序列中的元素复制/移动到目的位置, std::vector<int> v1{ -3,-2,-1 }; std::vector<int> v2{ 1,9 };//将v2最后三个元素改写为-3,-2,-1 auto iter=std::copy_backward(v1.begin(),v2.end());//v2={1,-3,-1}
将同一个序列中的两个有序子序列合并为一个单一的有序序列,并写入原序列。默认使用小于运算符进行比较,也可对小于运算符进行重定义。 std::vector<int> v{ 5,2 };//v的前3个元素与后3个元素都是按谓词升序排列的 std::inplace_merge(v.begin(),v.begin() + 3,int b) {return a > b; });//将大于定义为比较运算符 划分与排序算法划分与排序算法都提供了稳定与不稳定版本,稳定版本确保相等元素的相对位置保持不变,但是可能会消耗更多时间与内存。 划分算法
使用 struct A { int i; char c; }; std::vector<A>vA1{ {6,'g'},'h'},{-6,'t'},'s'},'p'} }; auto vA2 = vA1; //按A的i是否是正数进行划分 std::partition(vA1.begin(),vA1.end(),[](A a) {return a.i > 0; });//Visual Stdio 2019的运算结果是vA1={{6,'p'},'t'}},满足条件的{3,'s'}原来排在满足条件的{4,'p'}前面,划分后{3,'s'}排在了{4,'p'}的后面 std::stable_partition(vA2.begin(),vA2.end(),[](A a) {return a.i > 0; });//vA2={{6,'t'}},两部分内元素之间的相对位置没有改变
若所有满足条件的元素都排在不满足条件的元素之前,则返回 int array[5] = { 1,8 }; bool b = std::is_partitioned(array,array + 5,[](int i) {return i & 1; });//是否奇数排在偶数前面
输入序列必须是已用 int array[5] = { 1,8 }; auto iter = std::partition_point(array,[](int i) {return i & 1; });//iter指向最后一个奇数5的下一个位置,iter指向6
将序列中满足条件的元素复制到目的序列1,不满足条件的元素复制到目的序列2,返回一个迭代器 //将array中的奇数写入a1,偶数写入a2 int array[5] = { 1,8 }; int a1[5] = { 15,25,35,45,55 };//划分后a1={1,55} int a2[5] = { 10,20,30,40,50 };//划分后a2={6,50} auto iters = std::partition_copy(array,a1,a2,[](int a) {return a & 1; });//iters.first指向45,iters.second指向30 排序算法这些算法要求随机访问迭代器,默认使用小于运算符比较元素。除
对序列进行排序。 bool comp(int a,int b)//降序 { return a > b; } int main() { std::vector<int> v{ 7,8 }; std::sort(v.begin(),comp);//传入函数指针 }
std::vector<int> v{ 1,1 }; bool b = std::is_sorted(v.begin(),v.end());//是否升序,否 auto iter1 = std::is_sorted_until(v.begin(),int b) {return a < b; });//从开始到5都是升序的,iter1指向5后的4 auto iter2 = std::is_sorted_until(v.begin(),int b) {return a > b; });//只有最开始的元素是降序的,iter2指向第1个(从0开始)元素2
将 std::vector<int> v{ 7,8 }; std::partial_sort(v.begin(),v.begin() + 5,v.end());//将v中最小的5个元素排序,Visual Studio 2019排序结果为v={1,8}
排序输入范围中的元素,并将足够多的已排序元素放入 std::vector<int> v1{ 2,1 }; std::vector<int> v2(7,-1);//v2={1,-1} std::vector<int> v3(3,-1);//v3={1,3} std::partial_sort_copy(v1.begin(),v2.end()); std::partial_sort_copy(v1.begin(),v3.end());
参数 //取中位数 std::vector<int> v{ 2,1 }; auto iter = v.begin() + 2; std::nth_element(v.begin(),iter,v.end());//iter指向3 通用重排操作
这些算法会对序列中的元素进行重排,前两个算法 这些算法的基本版本都进行原址操作, 使用前向迭代器的重排算法
从序列中通过覆盖“删除”元素,返回一个指向最后有效元素之后的位置的迭代器。迭代器之后的元素不可再使用! std::vector<int> v{ 2,-1 }; auto iter = std::remove_if(v.begin(),[](int a) {return a < 0; });//v.size()==5 v.erase(iter,v.end());//v={2,4}
对相邻的重复元素,通过覆盖“删除”元素,返回一个指向最后有效元素之后的位置的迭代器。迭代器之后的元素不可再使用! std::vector<int> v{ 2,3 };//v.size()==9 std::sort(v.begin(),v.end());//需要先排序 auto iter = std::unique(v.begin(),v.end());//v.size()==9 v.erase(iter,v.end());//v={1,5}
让 std::string s("0123456789"); std::rotate(s.begin(),s.begin() + 2,s.end());//s="2345678901" 使用双向迭代器的重排算法
翻转序列元素, std::string s("abc"); std::reverse(s.begin(),s.end());//s="cba" 使用随机访问迭代器的重排算法
混洗序列中的元素,序列元素的一种随机排列。 std::default_random_engine e(static_cast<unsigned>(time(0))); std::vector<int> v{ 1,9 }; std::shuffle(v.begin(),e);//一种可能,v={5,9} 排列算法n个元素占据n个位置,改变不同元素的相对位置,就可以获取一个新的排列。比如由abc构成的序列有3!=6种排列:abc,acb,bac,bca,cab,cba。注意,这些排列是按升序排的。此外,生成排列的算法要求双向迭代器。
若两个序列有相同的元素,不论位置,则返回 std::string s1("abcd"); std::string s2("bcad"); bool b = std::is_permutation(s1.begin(),s1.end(),s2.begin(),s2.end());//true
std::string s("abcd"); do { std::cout << s << std::endl; } while (std::next_permutation(s.begin(),s.end())); 有序序列的集合算法这些算法都要求序列是有序的。除
如果第二个序列中的每个元素都包含在第一个序中,则返回 std::string s1("abcd");//有序 std::string s2("acd");//有序 bool b = std::includes(s1.begin(),s2.end());//true
取并集,目的序列中包含两个输入序列中所有出现过的元素,输入序列中不要有重复元素。 std::string s1("abcd");//有序 std::string s2("acde");//有序 std::string s3(8,' '); auto iter = std::set_union(s1.begin(),s2.end(),s3.begin()); s3.erase(iter,s3.end());//s3="abcde"
取交集,目的序列中包含两个输入序列中共同出现过的元素。 std::string s1("abcd");//有序 std::string s2("acde");//有序 std::string s3(4,' '); auto iter = std::set_intersection(s1.begin(),s3.end());//s3="acd"
集合1减去集合2,目的序列中包含出现在输入序列1但没出现在序列2中的元素。 std::string s1("abcd");//有序 std::string s2("acde");//有序 std::string s3(4,' '); auto iter = std::set_difference(s1.begin(),s3.end());//s3="b"
集合1加上集合2再减去二者的交集,目的序列中包含出现在一个序列但没出现在另一个序列中的元素。 std::string s1("abcd");//有序 std::string s2("acde");//有序 std::string s3(8,' '); auto iter = std::set_symmetric_difference(s1.begin(),s3.end());//s3="be" 最大值和最小值
返回 double m1 = std::min(2.0,6.2);//2.0 int m2 = std::max({ 2,-10,-8 },int b) {return std::abs(a) < std::abs(b); });//绝对值最大者,-10
返回一个 int a = 3,b = 2; auto ms = std::minmax(a,b); a = ms.first;//first是b的引用,现在a=2,b=2 b = ms.second;//second是a的引用,但是a已经更改为2,b=2 std::cout << a << ' ' << b << 'n';//2,2
前四个算法返回一个迭代器指向序列中的最小值/最大值,后两个返回一个迭代器 int array[10] = { 1,4 }; auto iters = std::minmax_element(array,array + 10); long long posDiff = iters.second - iters.first;//位置距离 int valDiff = *iters.second - *iters.first;//值的距离 字典序比较
判断序列1的字典序是否小于序列2,若小于,则返回 int array[6] = { 1,5 }; std::vector<int> v{ 1,4 }; std::deque<int> d{ 1,4 }; std::forward_list<int>l{ 1,9 }; bool b1 = std::lexicographical_compare(array,array + 6,v.begin(),v.end());//5不小于4,false bool b2 = std::lexicographical_compare(v.begin(),d.begin(),d.end());//相等需不小于,false bool b3 = std::lexicographical_compare(d.begin(),d.end(),l.begin(),l.end());//链表长度更短,false 完 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |