四、c++中的算法--非修改序列算法(非变易算法)
来源:互联网 发布:淘宝闲鱼怎么搜索 编辑:程序博客网 时间:2024/06/11 14:10
四、c++中的算法
标签(空格分隔): c++STL
简介
1.stl的算法一般采用“覆盖(overwrite)”模式而不是“安插(insert)”模式。调用时目标区间必须拥有最够的元素空间。
2.可以传递自定的函数
函数设计的通用:
- 使用模板了提供通用类型
- 使用迭代器访问容器
算法库:
- 非修改式序列算法:不改动容器中元素的次序和值,一般通过input迭代器和forward迭代器完成工作;
- 修改式序列算法:一般不直接更改元素值或者在复制到另一区间的过程中改变元素值,此算法还包括溢出性质和删除性质的算法。移除一般只是在逻辑上“移除”元素,不改变容器大小和容器中的元素个数。“移除”和“删除”是不同的算法。
- 排序和相关算法:包含多个排序函数和其他各种函数,包括集合操作等。不能以关联容器作为目标,因为关联容器元素被视为常数,不能变更。
- 通用数字算法: 一般包括将区间的内容累计,内部乘积,小计,计算相邻对象差等函数。
1.非修改序列算法
不需要使用循环而从序列中寻找出某些东西的基本工具。不会改变序列次序和元素值。
- for each 算法
- 元素计数算法
- 最小值和最大值算法
- 搜寻算法
- 区间比较算法
1.for each算法
定义:
for_each(Iterator begin, iterator end , proc op)
for_each 实现对区间[begin,end]中每个元素均调用进程op.
1.最普通的使用for_each算法
template<class T>void InsertValue(T & vec, int first, int last){ if (last > first){ for (int i = first; i < last;++i) vec.insert(vec.end(), i); } else { cout << "last<first!" << endl; }}void printItem(int elem){ cout << elem << " ";}int main(){ vector<int > vec; InsertValue(vec, 1, 10); for_each(vec.begin(),vec.end(), printItem); cout << endl;}
输出结果为:
1 2 3 4 5 6 7 8 9
2.for_each 中使用仿函数
仿函数:就是一个类使用时对象调用函数,又称为函数对象。其实现类中包含函数operator(),这个类就有了类似函数的行为。是stl六大组件(容器,配置器,迭代器,算法,配接器,仿函数)之一。
接下来使用自定义仿函数:Multiple<T>()
for_each(begin,end, Multiple<int>())
例子:
template<class T>void InsertValue(T & vec, int first, int last){ if (last > first){ for (int i = first; i < last;++i) vec.insert(vec.end(), i); } else { cout << "last<first!" << endl; }}void printItem(int elem){ cout << elem << " ";}template<class T>class Multiple {private: T value;public: Multiple(const T & t) :value(t){} void operator()(T& elem) const{ elem *= value; }};int main(){ vector<int > vec; InsertValue(vec, 1, 10); for_each(vec.begin(),vec.end(), printItem); cout << endl; for_each(vec.begin(), vec.end(), Multiple<int>(2)); //每个元素乘以2 for_each(vec.begin(), vec.end(), printItem); cout << endl;}
结果为:
1 2 3 4 5 6 7 8 92 4 6 8 10 12 14 16 18
3.for_each的返回值
函数原型为:
template< class InputIt, class UnaryFunction >UnaryFunction for_each( InputIt first, InputIt last, UnaryFunction f );
例子:
template<class InputIt, class UnaryFunction>UnaryFunction for_each(InputIt first, InputIt last, UnaryFunction f){ for (; first != last; ++first) { f(*first); } return f;}
例子:
//前面的部分省略class SUM{private: long sum_d; public: SUM() :sum_d(0){} void operator()(int elem){ sum_d += elem; } operator double(){ return static_cast<double>(sum_d); }};int main(){ vector<int > vec; InsertValue(vec, 1, 10); for_each(vec.begin(),vec.end(), printItem); cout << endl; for_each(vec.begin(), vec.end(), Multiple<int>(2)); //每个元素乘以2 for_each(vec.begin(), vec.end(), printItem); cout << endl; double sum = for_each(vec.begin(), vec.end(), SUM()); cout << "sum: "<<sum<<endl;}
输出结果为:
1 2 3 4 5 6 7 8 92 4 6 8 10 12 14 16 18sum: 90
2.元素计数算法
求元素的总个数。
函数形式为:
count(Iterator begin, Iterator end ,const T& value)count_if(Iterator begin ,Iterator end ,UnaryPredicate op)
说明:
1.在区间中统计值为value的个数
2.只有当op参数为真的时候,bool类型的返回值,才统计元素的个数。
例子:
#include <algorithm>#include <iostream>#include <vector>int main(){ int data[] = { 1, 2, 3, 4, 4, 3, 7, 8, 9, 10 }; std::vector<int> v(data, data+10); int target1 = 3; int target2 = 5; int num_items1 = std::count(v.begin(), v.end(), target1); int num_items2 = std::count(v.begin(), v.end(), target2); std::cout << "number: " << target1 << " count: " << num_items1 << '\n'; std::cout << "number: " << target2 << " count: " << num_items2 << '\n';}
输出结果为:
number: 3 count: 2number: 5 count: 0
例子2:
#include <algorithm>#include <iostream>#include <vector>int main(){ int data[] = { 1, 2, 3, 4, 4, 3, 7, 8, 9, 10 }; std::vector<int> v(data, data+10); int num_items1 = std::count_if(v.begin(), v.end(), [](int i) {return i % 3 == 0;}); std::cout << "number divisible by three: " << num_items1 << '\n';}
输出结果为;
number divisible by three: 3
3.最大值和最小值算法
最小值算法:
Iterator min_element(Iterator beg,Iterator end)Iterator min_element(Iterator beg, Iterator end, compFunc op)
最大值算法:
Iterator max_element(Iterator beg,Iterator end)Iterator max_element(Iterator beg, Iterator end, compFunc op)
上述两个形式参数:
1.第一种形式一“operator<”进行比较。
2.第二种以op(elem1,elem2)进行比较。
例子:
bool Absless(int elem1,int elem2){ return abs(elem1) < abs(elem2);}int main(){ vector<int> v{ 3, 1, 4, 1, 5, 9 ,-3}; vector<int>::iterator result = min_element(v.begin(), v.end());//最小值 cout << "min element at: " << *result << endl; result = min_element(v.begin(), v.end(),Absless);//最小绝对值 cout << "min element at: " << *result << endl;}
结果为:
min element at: -3min element at: 1
4. 搜寻算法
1.搜寻第一个匹配的元素
函数定义为:
Iterator find(Iterator begin, Iterator end, const T& value)Iterator find_if(Iterator begin, Iterator end, UnaryPredicate op)Iterator find_if_not(Iterator begin, Iterator end, UnaryPredicate op) [c++11]
说明:
1.第一个形式:返回区间值为value的第一个元素
2.第二个形式:寻找op值为真的第一个元素
3.第三个形式为c++11标准中: 寻找第一个是op返回false的元素
例子:
bool op(int elem1){ return elem1 < 3;}int main(){ int n1 = 3; int n2 = 5; std::vector<int> v{ 4,6,8,7,2,4 }; auto result1 = std::find(v.begin(), v.end(), n1); auto result2 = std::find_if(v.begin(), v.end(), op);//小于3的数 auto result3 = std::find_if_not(v.begin(), v.end(), op);//不小于3的数 if (result1 != v.end()) { std::cout << "v contains: " << n1 << '\n'; } else { std::cout << "v does not contain: " << n1 << '\n'; } if (result2 != v.end()) { std::cout << "v 存在小于3的数: " << *result2 << '\n'; } else { std::cout << "v 不才在小于3的数: "<< '\n'; } if (result3 != v.end()) { std::cout << "v 存在不小于3的数: " << *result3 << '\n'; } else { std::cout << "v 不小于3的数 " << '\n'; }}
结果为:
v does not contain: 3v 存在小于3的数: 2v 存在不小于3的数: 4
2.搜寻前n个匹配的值
函数为:
Iterator search_n(Iterator begin, Iterator end,Size count,constT& value)Iterator search_n(Iterator begin, Iterator end,Size count,constT& value,BinaryPredicate p)
说明:
1.第一个形式: 返回区间中“连续count个值为value”的序列的首位置,如果不存在,返回end
2.第二个形式: 使用区间中的每一个元素和value的比较,返回区间中满足op为真的连续count个元素的序列的开头位置,不满足返回end
例子:
bool op(int elem1,int elem2){ return elem1>elem2;}#include<iterator>int main(){ vector<int> vec = { -3, -2, -2, -2, -1, 0, 1, 2, 2, 3, 3, 3, 3, 4, 5, 6, 7, 7, 7, 7 }; vector<int>::iterator it1,it2;//distance需要不能使用const_iterator it1 = search_n(vec.begin(), vec.end(),4, 3);//寻找4个等于3的连续序列 it2 = search_n(vec.begin(), vec.end(), 5,3, op);//寻找大于3的5个元素 if (it1 != vec.end()) cout << "4个3的连续序列的起始位置为:" <<std::distance(vec.begin(),it1)<< endl; else{ cout << "没有4个3的连续序列! " << endl; } if (it2 != vec.end()) cout << "大于3的5个元素连续序列的起始位置为:" << std::distance(vec.begin(), it2) << endl; else{ cout << "没有大于3的5个元素的连续序列! " << endl; }}
值为:
4个3的连续序列的起始位置为:9大于3的5个元素连续序列的起始位置为:13
3.搜寻第一个子区间
函数定义为:
Iterator search(Iterator1 begin, Iterator1 end, Iterator2 searchchbegin, Iterator2 searchchend)Iterator search(Iterator1 begin, Iterator1 end, Iterator2 searchchbegin, Iterator2 searchchend,BinaryPredicate p)
说明:
1.两个函数返回区间内和子区间完全匹配的子区间开头位置,找不到的话,返回end,若子序列为空,返回begin
2.第二个函数在p为真的时候才执行。
例子:
bool op(int elem1,int elem2){ return elem1>elem2;}#include<iterator>int main(){ vector<int> vec1= {1,2,3,4,5,5,4,3,2,1 }; vector<int> vec2 = { 1,2, 3 }; vector<int>::iterator it1,it2; it1 = search(vec1.begin(), vec1.end(), vec2.begin(), vec2.end()); cout << "子区间位置为:" << std::distance(vec1.begin(), it1) << endl;//完全匹配 it2 = search(vec1.begin(), vec1.end(), vec2.begin(), vec2.end(),op); cout << "子区间位置为:" << std::distance(vec1.begin(), it2) << endl;//vec1大于vec2的序列}
输出为:
子区间位置为:0子区间位置为:1
4.搜寻最后一个子区间
函数由:
Iterator find_end(Iterator1 begin,Iterator1,end ,Iterator2 searchchbegin , Iterator2 searchend)Iterator find_end(Iterator1 begin,Iterator1,end ,Iterator2 searchchbegin , Iterator2 searchend,BinaryPredicate p)
说明:
1.两个函数都返回区间【begin,end】中和【searchchbegin,searchchend】匹配的最后一个子区间的开头位置。如果搜索失败,或者为空,返回end.
2.第二个函数只有在p为真的时候才有意义。
例子:
bool op(int elem1,int elem2){ return elem1>elem2;}#include<iterator>int main(){ vector<int> vec1= {1,2,3,4,5,4,3,2,1,2,3 }; vector<int> vec2 = { 1,2, 3 }; vector<int>::iterator it1,it2; it1 = find_end(vec1.begin(), vec1.end(), vec2.begin(), vec2.end()); cout << "子区间位置为:" << std::distance(vec1.begin(), it1) << endl;//完全匹配 it2 = find_end(vec1.begin(), vec1.end(), vec2.begin(), vec2.end(),op); cout << "子区间位置为:" << std::distance(vec1.begin(), it2) << endl;//vec1大于vec2的序列}-----------------------------------------输出为;子区间位置为:8子区间位置为:3
5.搜寻某些元素的第一次出现位置
函数为:
Iterator find_first_of(Iterator1 begin, Iterator1 end,Iterator2 searchchbegin,Iterator2 searchchend)Iterator find_first_of(Iterator1 begin, Iterator1 end,Iterator2 searchchbegin,Iterator2 searchchend, BiaryPredicate p)
函数的模板为:
template<class InputIt, class ForwardIt>InputIt find_first_of(InputIt first, InputIt last, ForwardIt s_first, ForwardIt s_last){ for (; first != last; ++first) { for (ForwardIt it = s_first; it != s_last; ++it) { if (*first == *it) { return first; } } } return last;}template<class InputIt, class ForwardIt, class BinaryPredicate>InputIt find_first_of(InputIt first, InputIt last, ForwardIt s_first, ForwardIt s_last, BinaryPredicate p){ for (; first != last; ++first) { for (ForwardIt it = s_first; it != s_last; ++it) { if (p(*first, *it)) { return first; } } } return last;}
说明:
1.两个函数都返回子区间[serachbegin,searchend]中任何元素在【begin,end】中出现的第一个位置,如果没有这样字的元素,返回end.
2.第二个函数只有在p为真的时候才有意义
例子:
bool op(int elem1,int elem2){ return elem1>elem2;}#include<iterator>int main(){ std::vector<int> v{ 0, 2, 3, 25, 5 }; std::vector<int> t{ 3, 19, 10, 4 }; auto result1 = std::find_first_of(v.begin(), v.end(), t.begin(), t.end()); auto result2 = std::find_first_of(v.begin(), v.end(), t.begin(), t.end(),op); if (result1 == v.end()) { std::cout << "不存在值为 3, 19, 10 or 4\n"; }else { std::cout << "发现匹配位置: " << std::distance(v.begin(), result1) << "\n"; } if (result2 == v.end()) { std::cout << "不存在大于 3, 19, 10 or 4的值\n"; }else { std::cout << "发现匹配位置: " << std::distance(v.begin(), result2) << "\n"; }}------------------------输出:发现匹配位置: 2发现匹配位置: 3
6.搜寻两个连续相等的元素
使用函数adjacent_find()
:
函数为:
//形式一template<class ForwardIt>ForwardIt adjacent_find(ForwardIt first, ForwardIt last){ if (first == last) { return last; } for (ForwardIt next = first;++next != last; ++first) { if (*first == *next) { return first;//一次循环就够了 } } return last;//为找到返回last}//形式二template<class ForwardIt, BinaryPredicate p>ForwardIt adjacent_find(ForwardIt first, ForwardIt last, BinaryPredicate p){ if (first == last) { return last; } for (ForwardIt next = first;++next != last; ++first) { if (p(*first, *next)) {//需要满足P return first; } } return last;}
其中,
ForwardIt adjacent_find( ForwardIt first, ForwardIt last );ForwardIt adjacent_find( ForwardIt first, ForwardIt last, BinaryPredicate p );
说明:ForwardIt
表示迭代器
1.两个函数都是返回迭代器范围内部两个连续的相同元素的位置,没有被找到,返回last.
2.第一个版本使用operator==比较的元素,第二个版本使用给定的二元谓词p.
例子:
#include <algorithm>#include <iostream>int main(){ std::vector<int> v1{0, 1, 2, 3, 40, 40, 5}; std::vector<int>::iterator result; result = std::adjacent_find(v1.begin(), v1.end()); if (result == v1.end()) { std::cout << "no matching adjacent elements"; } else { std::cout << "match at: " << std::distance(v1.begin(), result); }}--------------------------输出:match at: 4
5.区间比较算法
stl提供了三个比较函数:
- equal():比较两个容器对象相等
- mismatch():寻找两个容器对象两两相异的元素,如果找到相异点,将两个点返回一个pair对象;如果没有找到,将第一个元素的end元素和第二对象的对应元素返回成一个pair对象。
- lexicographical_compare():属于字典比较,元素一一比较:
(1).如果两个元素不相等,则两个元素的比较结果即为两个序列的比较结果
(2).如果两个容器中元素数量不相等,则元素较少的序列小于另一个序列,若第一序列较少,比较结果为true
(2).如果两个序列均没有更多元素比较,即序列相等,返回false
三个函数原型:
template< class InputIt1, class InputIt2 >bool equal( InputIt1 first1, InputIt1 last1, InputIt2 first2 );template< class InputIt1, class InputIt2, class BinaryPredicate >bool equal( InputIt1 first1, InputIt1 last1, InputIt2 first2, BinaryPredicate p );
1.如果区间[first1, last1)和区间[first2, first2 + (last1 - first1)相等,返回true,否则返回false.
2.第一个形式使用operator==判定两个元素是否相等,而重载形式2使用的是给定的谓词函数。
例子:
--省略--void test(const std::string& s){ if(std::equal(s.begin(), s.begin() + s.size()/2, s.rbegin())) { std::cout << "\"" << s << "\" 是一个回文\n"; } else { std::cout << "\"" << s << "\" 不是一个回文\n"; }}int main(){ test("radar"); test("hello");}---省略------------输出为:"radar" 是一个回文"hello" 不是是一个回文
mismatch():
函数原型:
template< class InputIt1, class InputIt2 >std::pair<InputIt1,InputIt2> mismatch( InputIt1 first1,InputIt1 last1,InputIt2 first2 );template< class InputIt1, class InputIt2, class BinaryPredicate >std::pair<InputIt1,InputIt2> mismatch( InputIt1 first1, InputIt1 last1, InputIt2 first2, BinaryPredicate p );
说明:
1.返回第一个不匹配,对两个范围中的元素:一个[first1,last1)和另一个开始在first2的序列。
2. 第一个版本的功能使用operator==来比较元素,第二个版本使用给定的二元谓词p.
3. 返回std::pair对象
例子:
#include<iterator>int main(){ vector<int> vec1= {1,2,3,4,5,6 }; vector<int> vec2 = { 1,2, 3,4,5,6,7 }; vector<int>::iterator it1,it2; pair<vector<int>::iterator, vector<int>::iterator> s; s = mismatch(vec1.begin(),vec1.end(),vec2.begin()); cout << "pair first: " << std::distance(vec1.begin(),s.first)<< " second: " <<std::distance(vec2.begin(),s.second) << endl;}
如果未找到相异点,那么返回第一个序列最后一个元素和第二列对应的元素。
【但是】,如果第二列长度小于第一列,当两列元素相同的时候,返回的pair对象第二个参数,即第二列的迭代器就会等于end(),也就是最后一个元素的后面位置,这个位置是无法解引用的,就会报错。
lexicographical_compare():
函数为:
template< class InputIt1, class InputIt2 >bool lexicographical_compare( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2 );template< class InputIt1, class InputIt2, class Compare >bool lexicographical_compare( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Compare comp );
说明:
1. 的第一个版本使用operator<
比较的元素,第二个版本使用给定的比较函数comp.
2. 第一个不匹配,元素定义的范围是字典“少”或“较大”比其他.
3. 如果一个范围是一个前缀的情况,在较短的范围是字典“小于”比其他.返回true
4. 如果两个范围有等同的元件,并具有相同的长度,则范围是字典“等于”.返回false
5. 空的范围是字典“少”比任何非空的范围内.返回false
6. 两个空的范围是字典“等于”.返回false
例子:
vector<int> vec1= {1,2,3,4,5,6 }; vector<int> vec2 = { 1,2, 3,4,5,6,7 }; vector<int> vec3; vector<int> vec4 = {1,2,3,4,5}; vector<int> vec5 = { 2, 2, 3, 4, 5 }; vector<int>::iterator it1,it2; bool flag; flag = lexicographical_compare(vec1.begin(), vec1.end(), vec2.begin(), vec2.end()); cout << "vec1 < vec2 :" << flag << endl; flag = lexicographical_compare(vec1.begin(), vec1.end(), vec3.begin(), vec3.end()); cout << "vec1 < vec3 :" << flag << endl; flag = lexicographical_compare(vec1.begin(), vec1.end(), vec4.begin(), vec4.end()); cout << "vec1 < vec4 :" << flag << endl; flag = lexicographical_compare(vec1.begin(), vec1.end(), vec5.begin(), vec5.end()); cout << "vec1 < vec5 :" << flag << endl;—————————————————————输出为:vec1 < vec2 :1vec1 < vec3 :0vec1 < vec4 :0vec1 < vec5 :1
- 四、c++中的算法--非修改序列算法(非变易算法)
- STL非变易算法
- 非变易算法
- 非变易算法
- stl非变易算法(一)
- stl非变易算法(二)
- STL(二十一)非变易算法
- STL非变易算法 - STL算法
- 非修改性序列算法之for_each
- 非修改性序列算法之mismatch
- 变易算法
- 变易算法
- STL算法库-非修改序列式操作(一)
- STL算法库-非修改序列式操作(二)
- STL非修改算法
- STL非修改算法
- STL非修改算法
- 变易算法 - STL算法
- 图像处理常用算法GPU实现三:基于模板匹配的边缘检测
- metadata lock
- java 类加载机制
- IDEA破解 2017 IDEA license server 激活(可用)
- 将C++的std::string类型变量赋值给char类型数组
- 四、c++中的算法--非修改序列算法(非变易算法)
- 将list转换为数组
- 最小生成树Prim算法学习
- 浅谈PHP中的数组和JS中的数组
- 转 gdb参数及命令详解 (已整理) core dump调试
- JDBC相关(二):数据库连接池技术原理,使用详解和常见的数据库连接池
- 解析分享SDK怎样传图片数据给分享平台
- uva 129 Krypton Factor
- 高德地图集成