1.定义
泛型算法是STL库里面定义的一些算法,这些算法可以用一个接口操作各种数据类型,因此成为泛型算法。大多算法定义在头文件algorithm和numeric中。意思就是可以用一个接口操作各种类型的算法就是泛型算法。
记住一些泛型算法,还是很必要的,有时候自己写的超长函数功能,其实调用一个库里面自带的函数就解决了。
2.一些泛型算法
[1]find(begin,end,value) :查找算法。begin到end是查找范围的迭代器,value是要找的值,返回值是第一个等于给定值的迭代器,如果没找到,则返回第二个参数表示找到了结尾。例如:
int target = 1;
vector<int> vec;
int array[4] = {1,2,3,4};
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
//查找一个vector if(find(vec.begin(), vec.end(), target) == vec.end()) printf("not find\n"); else printf("find\n"); //查找一个数组 if(find(&array[0], &array[3], target) == &ar[3]) printf("not find\n"); else printf("find\n");
find_if(begin, end, pred):查找算法。带自定义查找函数。意思就是对begin到end上面每一个元素判断pred(*iter) == true,则表示找到返回当前迭代器,找不到则返回end。例如:
bool isequal6(const int &v1) { return (v1 == 6); } class isequal5{ public: bool operator () (int& target) { return (target == 5); } }; class isequal{ public: isequal(int value):m_value(value){} bool operator () (int& target) { return (target == m_value); } int m_value; }; int main() { vector<int> vec1; vec1.push_back(1); vec1.push_back(5); vec1.push_back(6); if(find_if(vec1.begin(), vec1.end(), isequal6) != vec1.end()) //使用自定义函数 printf("find\n"); else printf("not find.\n"); if(find_if(vec1.begin(), vec1.end(), isequal5()) != vec1.end()) //使用仿函数 printf("find\n"); else printf("not find.\n"); if(find_if(vec1.begin(), vec1.end(), isequal(7)) != vec1.end()) //使用带参数的构造函数仿函数 printf("find\n"); else printf("not find.\n"); return 0; }
另外说一下这个仿函数,仿函数就是让对象拥有和函数名一样的调用方式。上面的仿函数代码解释如下:
class isequal5{ public: bool operator () (int& target) { return (target == 5); } }; class isequal{ public: isequal(int value):m_value(value){} bool operator () (int& target) { return (target == m_value); } int m_value; }; int main() { vector<int> vec1; vec1.push_back(1); vec1.push_back(5); vec1.push_back(6); /* 此处创建了一个对象i5,之后就可以把对象i5当成函数来使用了,例如i5(6) 因为重写的()运算符需要传入一个参数,所以这个i5仿函数也是需要传入一个参数 因此下面的find_if在查找的时候对每个iter执行了i5(*iter)操作。
也可以用上面的例子直接创建对象:find_if(vec1.begin(), vec1.end(), isequal5()),这里是为了解释,所以显式创建了一个i5
*/ isequal5 i5; if(find_if(vec1.begin(), vec1.end(), i5) != vec1.end()) printf("find\n"); else printf("not find.\n"); /* 此处创建了一个对象is,之后就可以把对象is当成函数来使用了,例如is(6) 因此下面的find_if在查找的时候对每个iter执行了is(*iter)操作。 */ isequal is(7); if(find_if(vec1.begin(), vec1.end(), is) != vec1.end()) printf("find\n"); else printf("not find.\n"); return 0; }
[2]accumulate(begin,end,init_value) :求和算法。begin到end是求和范围的迭代器,init_value是求和的初值。意思就是求前面范围的和,最后加上init_value。
int total; vector<int> vec; vec.push_back(1); vec.push_back(2); vec.push_back(3); total = accumulate(vec.begin(), vec.end(), 0); printf("total:%d\n", total);
[3]equal(v1.begin,v1.end,v2.begin) :比较算法。v1.begin到v1.end是比较的范围,v2.begin是一个迭代器的起始。如果相同则返回true,否则返回false。因为这个函数比较的时候是从范围的开始一直比较到范围的最后,所以第三个参数的长度应该至少等于比较的范围的长度,否则会比较到越界。这意思就是会从vec1.begin()取值和vec2.begin()开始比较,如果vec1有8个元素,则也会从vec2的迭代器一直加8次,所以vec2至少要有8个元素。
vector<int> vec1; vector<int> vec2; vec1.push_back(1); vec1.push_back(2); vec2.push_back(1); vec2.push_back(2); if(equal(vec1.begin(), vec1.end(), vec2.begin())) //比较vec1是否和vec2的每个元素是否相等(如果vec1的长度是n,则是比较vec2中的前n个) printf("equal.\n"); else printf("not equal.\n");
[4]fill(begin,end,value):填充算法。begin到end是填充的范围,value是要填充的值。类似memset()函数。
fill_n(begin,size,value):也是填充算法。begin是迭代器起始位置,size是填充的长度,value是填充的值。这个就是memset()函数。
vector<int> vec1(10); vector<int>::iterator it; fill(vec1.begin(), vec1.end(), 100); //把vec1每个元素填充为100 for(it=vec1.begin(); it!=vec1.end(); it++) printf("%d\n", *it);
fill_n(vec1.begin(), vec1.size(), 200); //把vec1每个元素填充为200
[5]back_inserter():插入迭代器。这个意思就是这是一个迭代器,并且可以插入值。给back_inserter赋值,其实就是push_back()。例如vector是空的时候,给it赋值是会core掉的(it=vec.begin();)。
vector<int> vec1; vector<int>::iterator it; //第一种赋值方式 back_inserter(vec1) = 1; back_inserter(vec1) = 2; //另外一种赋值方式 back_insert_iterator<vector<int> > backiter = back_inserter(vec1); *backiter = 10; backiter++; *backiter = 20; for(it=vec1.begin(); it!=vec1.end(); it++) printf("%d\n", *it); //调用fill_n赋值 fill_n(back_inserter(vec1), 10, 100); for(it=vec1.begin(); it!=vec1.end(); it++) printf("%d\n", *it);
[6]copy(v1.begin,v1.end,v2.begin):拷贝算法。v1.begin和v1.end是拷贝源的范围,v2.begin是拷贝目的迭代器的起始。所以v2的长度至少要等于v1的长度。这个函数的返回值是目的迭代器的尾部。为了顺序化写代码。
vector<int> vec1(5); vector<int> vec2(5); vector<int>::iterator it; fill_n(vec1.begin(), 5, 10); copy(vec1.begin(), vec1.end(), vec2.begin()); //把vec1的元素拷贝到vec2中 for(it=vec2.begin(); it!=vec2.end(); it++) printf("%d\n", *it);
[7]replace(begin,end,old_value,new_vlaue):替换算法。begin和end是查找的范围,old_value要搜索的值,new_value替换的值。意思就是把begin到end范围内的old_value替换为new_value。
vector<int> vec1; vector<int>::iterator it; vec1.push_back(1); vec1.push_back(2); vec1.push_back(3); replace(vec1.begin(),vec1.end(), 2, 10); //把vec1中的2的替换为10 for(it=vec1.begin(); it!=vec1.end(); it++) printf("%d\n", *it);
[8]sort(begin,end):排序算法。这个就是排序,另外可以有第三个参数,传入自定义的比较函数,另外也可以传入stl自带的比较函数模板。
stable_sort():稳定排序算法。这个用法和上面的是一样的。只不过这个函数对相同的元素可以在排序好后保持之前的相对位置,这个意思就是比如排序之前的序列中a等于b,并且a在b前面,则排序好后a还在b的前面,但是用sort排序就不一定是这样了。
bool islittle(const int &v1, const int &v2) { return (v1 < v2); } int main() { vector<int> vec1; vector<int>::iterator it, unique_end; vec1.push_back(1); vec1.push_back(2); vec1.push_back(6); vec1.push_back(3); vec1.push_back(2); sort(vec1.begin(),vec1.end()); //默认是升序排序 sort(vec1.begin(),vec1.end(), less<int>()); //升序排序 sort(vec1.begin(),vec1.end(), greater<int>()); //降序排序 sort(vec1.begin(),vec1.end(), islittle); //自定义比较函数 for(it=vec1.begin(); it!=vec1.end(); it++) printf("%d\n", *it); return 0; }
[9]unique(begin,end):去重算法。这个把begin到end之间重复的元素放到最后,返回最后一个不重复的迭代器。这个的意思就是把不重复的元素放到前面,最后的元素是什么已经无所谓了,删除就可以了。
vector<int> vec1; vector<int>::iterator it, unique_end; vec1.push_back(1); vec1.push_back(2); vec1.push_back(6); vec1.push_back(3); vec1.push_back(2); sort(vec1.begin(),vec1.end()); //sort之后是{1,2,2,3,6} unique_end = unique(vec1.begin(),vec1.end()); //unique之后是{1,2,3,6,6},unique_end指向最后的6 vec1.erase(unique_end, vec1.end()); //erase之后是{1,2,3,6}