标准模板库 STL(Standard Template Library)是C++标准库的一部分,是借助模板把常用的数据结构及算法封装在其中。掌握STL对于刷算法题有很大的帮助。写此文来记录总结下STL中的常用函数
常用遍历算法
以下算法都在头文件<algorithm>中
for_each 实现遍历容器
1
| for_each(iterator beg, iterator end, _func);
|
_func传入普通函数
1 2 3 4 5 6 7
| void vecPrint(int val) { cout << val << " "; } void test() { vector<int>v = { 2,3,43,324,234,123,2345,435,34 }; for_each(v.begin(), v.end(), vecPrint); }
|
运行结果
2 3 43 324 234 123 2345 435 34
_func传入仿函数
1 2 3 4 5 6 7 8 9 10
| class printFunctor{ public: void operator()(int val) { cout << val << " "; } }; void test() { vector<int>v = { 2,3,43,324,234,123,2345,435,34 }; for_each(v.begin(), v.end(), printFunctor()); }
|
运行结果
2 3 43 324 234 123 2345 435 34
1
| transform(iterator beg1, iterator end1, iterator beg2, _func);//beg1 源容器开始迭代器 end1 源容器结束迭代器 beg2 目标容器开始迭代器 _func 函数或者函数对象
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Trans { public: int operator()(int val) { return val+10; } }; void test() { vector<int>v = { 1,2,3,4,5,6,7,8,9 }; vector<int>vTarget; vTarget.resize(v.size()); transform(v.begin(), v.end(),vTarget.begin(), Trans()); for_each(vTarget.begin(), vTarget.end(), printFunctor()); }
|
运行结果
11 12 13 14 15 16 17 18 19
常用查找算法
find查找指定元素
1
| find(iterator beg.iterator end,value)//value为查找的元素,找到返回指定元素的迭代器,否则返回end()
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| void test() { vector<int>v = { 1,2,3,4,5,6,7,8,9 }; vector<int>::iterator it; int toFind=1; cout << "原始数据展示:" << endl; for_each(v.begin(), v.end(), printFunctor()); cout << endl; cout << endl; while (toFind) { cout << "待查找值:"; cin >> toFind; it = find(v.begin(), v.end(), toFind); if (it != v.end()) { cout << "找到" << toFind << "了" << endl; } else cout << "找不着" << endl; } }
|
运行结果
原始数据展示:
1 2 3 4 5 6 7 8 9
待查找值:2
找到2了
待查找值:0
找不着
以上是对常用数据类型查找的示例演示,但试想以下,如果数据类型不是常用的int,char,string之类的,而是自己定义的结构体类型,我们知道如果要判定自己定义的数据类型是否相等要写重载函数的,编译器是不支持自定义数据类型的判等之类的操作的,所以对于自定义数据类型,find函数自然也不会执行成功,该如何修改程序呢?
首先把自定义数据类型与重载函数设计好
1 2 3 4 5 6 7 8 9
| class Person { public: string p_name; int p_age; Person(string name, int age) { this->p_age = age; this->p_name = name; } };
|
接下来就以查找成功的案例演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| void test() { vector<Person>v; Person p1("吴京", 45); Person p2("郭帆", 40); Person p3("吴孟达", 60); Person p4("李雪健", 71); v.push_back(p1); v.push_back(p2); v.push_back(p3); v.push_back(p4); vector<Person>::iterator it; it=find(v.begin(), v.end(), p1); if (it != v.end()) { cout << "找着" << it->p_name << "了 " <<"年龄:"<<it->p_age<<endl; } }
|
运行结果
找着吴京了 年龄:45
find_if 按条件查找元素
1
| find_if(iterator beg,iterator end, _Pred);//_Pred 函数或者谓词
|
以在1-10数值查找大于5的数为例,来看一看 find_if 的效果
写一个判定大于5的谓词
1 2 3 4 5 6
| class GT5 { public: bool operator()(int val) { return val>5; } };
|
接下来展示一下 find_if 的效果
1 2 3 4 5
| void test() { vector<int>v = { 1,2,3,4,5,6,7,8,9,10 }; vector<int>::iterator it= find_if(v.begin(), v.end(), GT5()); cout << *it; }
|
运行结果
6
可以看到,函数返回的是查找到的第一个符合条件的元素的迭代器。
对于自定义类型的数据,需要在写谓词的时候写出适合该数据类型的合适方法。比如拿之前写好的Person类,你需要比较年龄,就写关于年龄比较的仿函数。
adjacent_find 查找相邻重复元素
1
| adjacent_find(iterator beg, iterator end);
|
很简单,返回第一个相邻的重复元素
对于自定义的数据类型需要单独写函数或者仿函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| void showPerson(const Person& p) { cout << p.p_name << " : " << p.p_age << endl;
} void test() { vector<Person>v; Person p1("吴京", 45); Person p2("郭帆", 40); Person p3("吴孟达", 60); Person p4("李雪健", 71); v.push_back(p1); v.push_back(p1); v.push_back(p2); v.push_back(p2); v.push_back(p3); v.push_back(p4); vector<Person>::iterator it; it=adjacent_find(v.begin(), v.end()); for_each(v.begin(), v.end(), showPerson); if (it != v.end()) { cout <<"相邻重复元素" << it->p_name << " 的年龄:" << it->p_age << endl; } }
|
运行结果
吴京 : 45
吴京 : 45
郭帆 : 40
郭帆 : 40
吴孟达 : 60
李雪健 : 71
相邻重复元素吴京 的年龄:45
binary_search 二分查找
返回的是布尔类型
适用于有序数列
1
| bool binary_search(iterator beg, iterator end, value);
|
1 2 3 4
| void test() { vector<int>v = { 2,2,3,3,4,4,7,8,9,10 }; cout<<"查找7找到没?"<<binary_search(v.begin(), v.end(), 7); }
|
运行结果
查找7找到没?1
count 统计元素个数
1
| count(iterator beg,iterator end,value);
|
统计自定义数据类型要实现==的重载
count_if 按条件统计元素个数
1
| count_if(iterator beg, iterator end, _Pred);
|
方法同样是分内建数据类型和自定义数据类型两种实现方式,归根到底的区别在于谓词的设计上的不同
1 2 3 4 5 6 7 8 9 10 11 12
| class FindByAge { public: bool operator()(const Person &P) { return P.p_age ==40; } }; class GT5 { public: bool operator()(int val) { return val > 5; } };
|
常见排序算法
sort 容器内数据排序
1
| sort(iterator beg, iterator end, _Pred);
|
将容器内的数据逆序案例:
1 2 3 4 5 6 7 8 9 10 11 12
| class decrease { public: bool operator()(int val1, int val2) { return val1 > val2; } }; void test() { vector<int>v = { 2,2,3,3,4,4,7,8,9,10 }; sort(v.begin(), v.end(),decrease()); for_each(v.begin(), v.end(), printFunctor());
}
|
运行结果
10 9 8 7 4 4 3 3 2 2
random_shuffle 指定范围内的元素随机调整次序
使用时加随机数种子,使数据更有随机性
1
| random_shuffle(iterator beg, iterator end);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| void showPerson(const Person& p) { cout << " " << p.p_name << " : " << p.p_age;
} void test() { vector<Person>v; srand((unsigned int)time(NULL)); Person p1("吴京", 40); Person p2("郭帆", 40); Person p3("吴孟达", 60); Person p4("李雪健", 71); v.push_back(p1); v.push_back(p2); v.push_back(p2); v.push_back(p3); v.push_back(p3); v.push_back(p4); v.push_back(p4); vector<Person>::iterator it; cout << "原始数据:"; for_each(v.begin(), v.end(), showPerson); random_shuffle(v.begin(), v.end()); cout <<endl<< "洗牌后的数据: "; for_each(v.begin(), v.end(), showPerson); }
|
运行结果
原始数据: 吴京 : 40 郭帆 : 40 郭帆 : 40 吴孟达 : 60 吴孟达 : 60 李雪健 : 71 李雪健 : 71
洗牌后的数据: 吴孟达 : 60 郭帆 : 40 李雪健 : 71 郭帆 : 40 吴京 : 40 李雪健 : 71 吴孟达 : 60
merge 合并两个容器,并存储到另一个容器
1 2 3 4 5 6 7 8 9 10 11 12 13
| void test() { vector<int>v1; vector<int>v2; vector<int>v3; for (int i = 10;i >0;i--) { v1.push_back(i); v2.push_back(i+3); } v3.resize(v1.size() + v2.size()); merge(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin(),decrease()); for_each(v3.begin(), v3.end(), printFunctor());
}
|
运行结果_
13 12 11 10 10 9 9 8 8 7 7 6 6 5 5 4 4 3 2 1
默认是按升序排列,如果升序排列需要排序的两个数列皆为升序;如是自定义数据类型或者如案例中非默认方式排列,就需要自己写相关的谓词。注意升序则都升序,降序都降序,否则运行会中止
__reverse __反转
1
| reverse(iterator beg, iterator end);
|
常用拷贝和替换算法
copy
1
| copy(iterator beg, iterator end,iterator dest)//dest目标容器起始迭代器
|
下面的案例是拷贝一个自定义数据类型容器的案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| class Person { public: string p_name; int p_age; Person(string name="", int age = 0) { this->p_age = age; this->p_name = name; } bool operator==(const Person& p) { if (this->p_name == p.p_name && this->p_age == p.p_age)return true; else return false; }
}; void test() { vector<Person>v; vector<Person>v1;
Person p1("吴京", 40); Person p2("郭帆", 40); Person p3("吴孟达", 60); Person p4("李雪健", 71); v.push_back(p1); v.push_back(p2); v.push_back(p2); v.push_back(p3); v.push_back(p3); v.push_back(p4); v.push_back(p4); v1.resize(v.size()); vector<Person>::iterator it; cout << "原始数据:"; for_each(v.begin(), v.end(), showPerson); copy(v.begin(), v.end(), v1.begin()); cout <<endl<< "拷贝后的数据: "; for_each(v1.begin(), v1.end(), showPerson); }
|
运行结果
原始数据: 吴京 : 40 郭帆 : 40 郭帆 : 40 吴孟达 : 60 吴孟达 : 60 李雪健 : 71 李雪健 : 71
拷贝后的数据: 吴京 : 40 郭帆 : 40 郭帆 : 40 吴孟达 : 60 吴孟达 : 60 李雪健 : 71 李雪健 : 71
replace 将容器内指定范围的旧元素修改为新元素
1
| replace(iterator beg, iterator end, oldvalue, newvalue)
|
下列案例将吴京的数据替换成郭帆的数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| void test1() { vector<Person>v; vector<Person>v1;
Person p1("吴京", 40); Person p2("郭帆", 40); Person p3("吴孟达", 60); Person p4("李雪健", 71); v.push_back(p1); v.push_back(p2); v.push_back(p2); v.push_back(p3); v.push_back(p3); v.push_back(p4); v.push_back(p4); vector<Person>::iterator it; cout << "原始数据:"; for_each(v.begin(), v.end(), showPerson); replace(v.begin(), v.end(), p1,p2); cout <<endl<< "替换后的数据: "; for_each(v.begin(), v.end(), showPerson); }
|
运行结果
原始数据: 吴京 : 40 郭帆 : 40 郭帆 : 40 吴孟达 : 60 吴孟达 : 60 李雪健 : 71 李雪健 : 71
替换后的数据: 郭帆 : 40 郭帆 : 40 郭帆 : 40 吴孟达 : 60 吴孟达 : 60 李雪健 : 71 李雪健 : 71
replace 是将所有的吴京都替换成郭帆
replace_if 将区间内满足条件的元素替换成指定元素
1
| replace_if(iterator beg, iterator end, _pred, newvalue);
|
将年龄大于40人的数据都替换成郭帆
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| class ageG40 { public: bool operator()(const Person &P) { return P.p_age > 40; } }; void test1() { vector<Person>v; vector<Person>v1;
//创建数据 Person p1("吴京", 40); Person p2("郭帆", 40); Person p3("吴孟达", 60); Person p4("李雪健", 71); v.push_back(p1); v.push_back(p2); v.push_back(p2); v.push_back(p3); v.push_back(p3); v.push_back(p4); v.push_back(p4); vector<Person>::iterator it;//定义一个迭代器 cout << "原始数据:"; for_each(v.begin(), v.end(), showPerson); replace_if(v.begin(), v.end(),ageG40(), p2);//将年龄大于40的都替换成郭帆数据 cout <<endl<< "替换后的数据: "; for_each(v.begin(), v.end(), showPerson); }
|
运行结果
原始数据: 吴京 : 40 郭帆 : 40 郭帆 : 40 吴孟达 : 60 吴孟达 : 60 李雪健 : 71 李雪健 : 71
替换后的数据: 吴京 : 40 郭帆 : 40 郭帆 : 40 郭帆 : 40 郭帆 : 40 郭帆 : 40 郭帆 : 40
swap
互换两个容器的元素
1
| swap(container c1, container c2);//c1, c2两个同种类型的容器
|
算术生成算法
#include <numeric>
accumulate 计算容器元素累计总和
1
| accumulate(iterator beg,iterator end, value);//计算容器元素累计总和 value起始值
|
fill 容器填充
1
| fill (iterator beg.iterator end, value);//向容器填充value
|
集合算法
交集 set_intersection
1
| set_intersection(iterator beg1, iterator end1,iterator beg2, iterator end2,iterator dest)//dest目标容器起始迭代器
|
并集 set_union
差集 set_difference