四. 常用算法
4.1 函数对象-仿函数
重载函数调用操作符的类,其对象常称为函数对象(function object),即它们是行为类似函数的对象,也叫仿函数(functor),其实就是重载“()”操作符,使得类对象可以像函数那样调用。
注意:
1.函数对象(仿函数)是一个类,不是一个函数。
2.函数对象(仿函数)重载了”() ”操作符使得它可以像函数一样调用。
分类:
假定某个类有一个重载的operator(),而且重载的operator()要求获取一个参数,我们就将这个类称为“一元仿函数”(unary functor);相反,如果重载的operator()要求获取两个参数,就将这个类称为“二元仿函数”(binary functor)。
函数对象的作用主要是什么?
STL提供的算法往往都有两个版本,其中一个版本表现出最常用的某种运算,另一版本则允许用户通过template参数的形式来指定所要采取的策略。
总结:
1、函数对象通常不定义构造函数和析构函数,所以在构造和析构时不会发生任何问题,避免了函数调用的运行时问题。
2、函数对象超出普通函数的概念,函数对象可以有自己的状态
3、函数对象可内联编译,性能好。用函数指针几乎不可能
4、模版函数对象使函数对象具有通用性,这也是它的优势之一
示例代码:
class MyPrint
{
public:
void operator()( int num) {
cout << "num " << num << endl;
count++;
}
int count = 0; //测试时不完全一致,类中无法进行初始化
};
void MyPrint2(int num ) {
cout << "num " << num << endl;
}
void test01() {
//MyPrint是一个类 ,而不是函数。使用上像函数的形式,仿函数
MyPrint myPrint;
myPrint(111);
MyPrint()(1000); //匿名对象
//函数
MyPrint2(111);
}
//函数对象超出普通函数概念,内部可以保存状态
void test02() {
MyPrint myPrint;
myPrint(111);
myPrint(111);
cout << "myPrint使用次数:" << myPrint.count << endl;
}
//函数对象作为参数
void doPrint(MyPrint print, int num) {
print(num);
}
void test03() {
doPrint(MyPrint(), 20); //传进去一个匿名对象即可
}
4.2 谓词 && find_if
谓词是指普通函数或重载的operator()返回值是bool类型的函数对象(仿函数)。如果operator接受一个参数,那么叫做一元谓词,如果接受两个参数,那么叫做二元谓词,谓词可作为一个判断式。
find_if返回值是个迭代器。
示例代码:
//一元谓词
class GreaterThen20
{
public:
bool operator()(int val) { return val > 20; }
};
void test01()
{
vector<int>v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
//查找第一个大于20的数字
//第三个参数 函数对象 匿名对象
vector<int>::iterator pos = find_if(v.begin(), v.end(), GreaterThen20());
if (pos!=v.end()) {
cout << "找到大于20的数字为:" << *pos << endl;
} else {
cout << "未找到" << endl;
}
}
//二元谓词
class MyCompare
{
public:
bool operator()(int v1 ,int v2) { return v1 > v2; }
};
void test02()
{
vector<int>v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
//从大到小排序
sort(v.begin(), v.end(), MyCompare());
//匿名函数 lambda表达式 [](){};
for_each(v.begin(), v.end(), [](int val){ cout << val << " "; });
}
4.3 内建函数对象 #include <functional>
STL内建了一些函数对象,分为:算数类函数对象,关系运算类函数对象,逻辑运算类仿函数。
这些仿函数所产生的对象,用法和一般函数完全相同,当然我们还可以产生无名的临时对象来履行函数功能。
使用内建函数对象,需要引入头文件 #include。
greater、less的比较先后顺序与常识是一直的,3 > 2 greater(3, 2)
6个算数类函数对象,除了negate是一元运算,其他都是二元运算。
template<class T> T plus<T>//加法仿函数
template<class T> T minus<T>//减法仿函数
template<class T> T multiplies<T>//乘法仿函数
template<class T> T divides<T>//除法仿函数
template<class T> T modulus<T>//取模仿函数
template<class T> T negate<T>//取反仿函数
6个关系运算类函数对象,每一种都是二元运算。
template<class T> bool equal_to<T>//等于
template<class T> bool not_equal_to<T>//不等于
template<class T> bool greater<T>//大于
template<class T> bool greater_equal<T>//大于等于
template<class T> bool less<T>//小于
template<class T> bool less_equal<T>//小于等于
逻辑运算类运算函数,not为一元运算,其余为二元运算。
template<class T> bool logical_and<T>//逻辑与
template<class T> bool logical_or<T>//逻辑或
template<class T> bool logical_not<T>//逻辑非
内建函数对象举例:
void test01()
{
//template<class T> T plus<T> 加法仿函数
plus<int> p;
cout << p(1, 1) << endl;
//template<class T> T negate<T> 取反仿函数
negate<int>n;
cout << n(10) << endl;
//使用匿名对象的方式
int a = minus<int>()(12, 2);
int b = negate<int>()(5);
cout << a << endl;
}
void test02()
{
//template<class T> bool greater<T>//大于
cout << equal_to<int>()(2, 2) << endl; // 2 equal_to 2
cout << not_equal_to<int>()(2, 3) << endl; // 2 not_euqal_to 3
cout << greater<int>()(2, 3) << endl; // 2 greater 3
cout << greater_equal<int>()(2, 2) << endl; // 2 greater_equal 2
cout << less<int>()(2, 2) << endl; // 0
cout << less_equal<int>()(2, 2) << endl; // 1
vector<int>v;
v.push_back(21);v.push_back(1);v.push_back(25);v.push_back(13);
sort(v.begin(), v.end(), greater<int>());
for_each(v.begin(), v.end(), [](int val){cout << val << endl;});
}
void test03()
{
//template<class T> bool logical_and<T> 逻辑与
cout << logical_and<int>()(33, 0) << endl;
//template<class T> bool logical_or<T> 逻辑或
cout << logical_or<int>()(33, 0) << endl;
//template<class T> bool logical_not<T> 逻辑非
cout << logical_not<int>()(0) << endl;
}
4.4 函数对象适配器
使用函数对象适配器,自定义函数对象时需要继承binary_function或unary_function,并且重载的()函数需要声明为常函数const。
(1) 函数适配器bind1st bind2nd
现在有这个需求:在遍历容器的时候,我希望将容器中的值全部加上100之后显示出来,怎么做?我们直接给函数对象绑定参数 编译阶段就会报错。使用函数适配器bind1st bind2nd将二元函数对象转为一元函数对象。
bind1st:将参数绑定为函数对象的第一个参数
bind2nd:将参数绑定为函数对象的第二个参数
如果我们想使用绑定适配器,需要我们自己的函数对象继承binary_function或者unary_function(binary:二进制的,二元的 unary:一元的)。根据我们函数对象是一元函数对象 还是二元函数对象。
使用示例:
//1.继承binary_function 指明参数、返回值类型<int, int, void>
//实验测试,类型是int &或const int&,都编译通不过。只有在int ,int ,void时才能通过
class myprint:public binary_function<int, int ,void>
{
public:
//2.重载(),定义为常函数const,不能修改普通成员变量。如果不定义为const,无法通过
void operator()(int v1, int v2) const {
cout << "v1 = " << v1 << " v2 = " << v2 << " v1 + v2 = " << v1 + v2 << endl;
}
};
void test() {
vector<int>v;
for (int i = 0; i < 10; i++) {
v.push_back(i);
}
//3.绑定 bind1st bind2nd
for_each(v.begin(), v.end(), bind1st(myprint(), 100)); //v1=100
for_each(v.begin(), v.end(), bind2nd(myprint(), 100)); //v2=100
}
(2) 取反适配器 not1 not2
not1对一元函数对象取反,not2 对二元函数对象取反。
示例代码:
//实验测试,传参类型可以是int &, const int&都可以
class greaterthan5:public unary_function<int,bool>
{
public:
bool operator()(int val) const{ return val > 5; }
};
class mygreater:public binary_function<int, int, bool>
{
public:
bool operator()(int v1, int v2) const { return v1 > v2; }
};
void test() {
vector<int>v; vector<int>::iterator it;
for (int i = 0; i < 10; i++) { v.push_back(i); }
//not1(greaterthan5()) 不大于5 0
it = find_if(v.begin(), v.end(), not1(greaterthan5()));
if (it != v.end()) { cout << "找到了第1个不大于5的数为:" << *it << endl; }
//bind2nd 自定义比较对象的值 8
//it = find_if(v.begin(), v.end(), bind2nd(mygreater(), 7));
it = find_if(v.begin(), v.end(), bind2nd(greater<int>(), 7));
if (it != v.end()) {
cout << "找到了第1个大于7的数为:" << *it << endl;
}
//not1(bind2nd(greater<int>(), 7)) 0
it = find_if(v.begin(), v.end(), not1(bind2nd(greater<int>(), 7)));
if (it != v.end()) {
cout << "找到了第1个不大于7的数为:" << *it << endl;
}
}
void test() {
vector<int>v;
v.push_back(32); v.push_back(5); v.push_back(15); v.push_back(7);
sort(v.begin(), v.end(), less<int>()); //从小到大排序
for_each(v.begin(), v.end(), [](int val){ cout << val << endl; });
//排序 二元函数对象
sort(v.begin(), v.end(), not2(less<int>())); //从大到小排序
for_each(v.begin(), v.end(), [](int val){ cout << val << endl; });
}
(3) 函数指针适配器 ptr_fun
示例代码:
//这里也只能传int,不能是int &或const int &
void myprint(int v1, int v2) {
cout << "v1 = " << v1 << " v2 = " << v2 << " v1+v2= " << v1+v2 << endl;
}
void test() {
vector<int>v;
for (int i = 0; i < 10; i++) { v.push_back(i); }
for_each(v.begin(), v.end(), bind2nd(ptr_fun(myprint), 100));
}
(4) 成员函数适配器 mem_fun_ref mem_fun
如果容器存放的是对象实体,用mem_fun_ref。如果存放的是对象指针,用mem_fun。
示例代码:
class person:public binary_function<person&, int, void>
{
public:
person(string m_name, int m_age):name(m_name), age(m_age) {}
void show_person() { cout << this->name << " age is " << this->age << endl; }
void plus_age() { this->age += 10; }
private:
string name;
int age;
};
/******************** mem_fun_ref *********************/
void test() {
vector<person>v;
person p1("xiao hong", 13), p2("xiao liang", 18), p3("xiao wang", 17);
v.push_back(p1); v.push_back(p2); v.push_back(p3);
for_each(v.begin(), v.end(), mem_fun_ref(&person::show_person));
for_each(v.begin(), v.end(), mem_fun_ref(&person::plus_age));
for_each(v.begin(), v.end(), mem_fun_ref(&person::show_person));
}
/********************* mem_fun *************************/
void test() {
vector<person*>v;
person p1("xiao hong", 13);
person p2("xiao liang", 18);
person p3("xiao wang", 17);
v.push_back(&p1); v.push_back(&p2); v.push_back(&p3);
for_each(v.begin(), v.end(), mem_fun(&person::show_person));
for_each(v.begin(), v.end(), mem_fun(&person::plus_age));
for_each(v.begin(), v.end(), mem_fun(&person::show_person));
}
4.5 算法概述
算法主要是由头文件<algorithm> <functional> <numeric>组成。
<algorithm>是所有STL头文件中最大的一个,其中常用的功能涉及到比较,交换,查找,遍历,复制,修改,反转,排序,合并等…
<numeric>体积很小,只包括在几个序列容器上进行的简单运算的模板函数.
<functional> 定义了一些模板类,用以声明函数对象。
4.5.1 遍历算法
for_each
/*
遍历算法 遍历容器元素
@param beg 开始迭代器
@param end 结束迭代器
@param _callback 函数回调或者函数对象
@return 函数对象
for_each(iterator beg, iterator end, _callback);
template<class _InIt,class _Fn1> inline
void for_each(_InIt _First, _InIt _Last, _Fn1 _Func)
{
for (; _First != _Last; ++_First)
_Func(*_First);
}
*/
for_each用法示例:
// 1. for_each的参数可以是普通函数或函数对象
void myprint(int v) { cout << v << endl; }
struct myPrint01
{
void operator()(int v) { cout << v << endl; }
};
void test01() {
vector<int>v;
for (int i = 0; i < 10;i++)
{
v.push_back(i);
}
//普通函数
for_each(v.begin(), v.end(), myPrint);
//函数对象
for_each(v.begin(), v.end(), myPrint01());
}
//2.for_each有返回值,返回函数对象
struct myPrint02
{
void operator()(int v) { cout << v << endl; m_Count++; }
int m_Count;
};
void test02() {
vector<int>v;
for (int i = 0; i < 10; i++) { v.push_back(i); }
myPrint02 print2 = for_each(v.begin(), v.end(), myPrint02());
cout << print2.m_Count << endl;
}
//3 for_each可以绑定参数进行输出
struct myPrint03 :public binary_function<int,int,void>
{
void operator()(int v ,int start) const
{ cout << v + start << endl; }
};
void test03() {
vector<int>v;
for (int i = 0; i < 10; i++) { v.push_back(i); }
for_each(v.begin(), v.end(), bind2nd(myPrint03(), 10000));
}
4.5.2 查找算法
(1) find
/*
find算法 查找元素
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param value 查找的元素
@return 返回查找元素的位置
find(iterator beg, iterator end, value)
*/
示例代码:查找自定义数据类型
class person
{
public:
person(string m_name, int m_age):name(m_name), age(m_age){}
bool operator==(const person &p) //const必不可少,不然编译通不过
{
if ((this->name == p.name) && (this->age == p.age))
return true;
return false;
}
string name;
int age;
};
void test() {
vector<person>v;
person p1("xiao hong", 17), p2("xiaoliang", 15), p3("xiaoliang", 16);
v.push_back(p1); v.push_back(p2);
vector<person>::iterator it = find(v.begin(), v.end(), p2);
if (it != v.end()) {
cout << "找到了" << endl;
} else { cout << "未找到" << endl; }
it = find(v.begin(), v.end(), p3);
if (it != v.end()) {
cout << "找到了" << endl;
} else { cout << "未找到" << endl; }
}
(2) find_if
遍历容器,找到符合条件的(true)返回,如果没找到,返回v.end
/*
find_if算法 条件查找
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param callback 回调函数或者谓词
@return 迭代器
*/
find_if(iterator beg, iterator end, _callback);
示例代码:
bool test01(int val)
{
cout << val << endl;
if (val > 5)
return true;
return false;
}
void test() {
vector<int>v;
for (int i = 0; i < 10; i++) v.push_back(i);
vector<int>::iterator it = find_if(v.begin(), v.end(), test01);
if (it != v.end()) {
cout << "找到了" << *it << endl;
} else { cout << "未找到" << endl; }
}
/********************* bind2nd *****************************/
class test02:public binary_function<int, int ,bool>
{
public:
bool operator()(int val, int v2) const
{
cout << val << endl;
if (val > v2)
return true;
return false;
}
};
void test() {
vector<int>v;
for (int i = 0; i < 10; i++) v.push_back(i);
vector<int>::iterator it = find_if(v.begin(), v.end(), bind2nd(test02(), 8));
if (it != v.end()) {
cout << "找到了" << *it << endl;
} else { cout << "未找到" << endl; }
}
/***************** 查找自定义数据类型 ***************/
class person
{
public:
person(string m_name, int m_age):name(m_name),age(m_age){}
string name;
int age;
};
class test02:public binary_function<person*, person* ,bool>
{
public:
bool operator()(person* val, person* v2) const
{
cout << val->name << endl;
if ((val->name == v2->name) && (val->age == v2->age))
return true;
return false;
}
};
void test() {
vector<person*>v;
person p1("xiao hong", 18), p2("xiao liang", 18);
v.push_back(&p1); v.push_back(&p2);
person *p = new person("xiao liang", 18);
vector<person*>::iterator it = find_if(v.begin(), v.end(), bind2nd(test02(), p));
if (it != v.end()) {
cout << "找到了" << (*it)->name << endl;
} else { cout << "未找到" << endl; }
}
(3) adjacent_find
adjacent [əˈdʒesənt]相邻的
/*
adjacent_find算法 查找相邻重复元素
@param beg 容器开始迭代器
@param end 容器结束迭代器
@return 返回相邻元素的第一个位置的迭代器
adjacent_find(iterator beg, iterator end, _callback);
*/
adjacent:邻近的
示例代码:
void test() {
vector<int>v;
v.push_back(2); v.push_back(3); v.push_back(3); v.push_back(5);
vector<int>::iterator it = adjacent_find(v.begin(), v.end());
if (it != v.end()) {
cout << "找到了3, 它的前1个元素是" << *(it-1) << " 下1个是"<< *(it+1) << endl;
} else { cout << "未找到" << endl; }
}
(4) binary_search
/*
binary_search算法 二分查找法 binary: [ˈbaɪnəri] adj:二进制的,二元的,二态的
注意: 在无序序列中不可用
有序序列:元素按照升序或降序存储。vector(0 1 2 3 4这样有顺序的)或者set容器这种自动排序容器
无序序列:vector(22 33 12)这样无序的
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param value 查找的元素
@return bool 查找返回true 否则false
bool binary_search(iterator beg, iterator end, value);
*/
示例代码:
void test() {
vector<int>v;
set<int>myset;
bool ret;
v.push_back(12); v.push_back(22); v.push_back(9);
//无序容器,有可能找到有可能找不到,看运气
for_each(v.begin(), v.end(), [](int val){cout << val << endl;});
ret = binary_search(v.begin(), v.end(), 9); //没找到
if (ret) {
cout << "找到了" << endl;
} else {
cout << "没找到" << endl;
}
//变为有序序列,就能找到了
sort(v.begin(), v.end());
ret = binary_search(v.begin(), v.end(), 9); //找到了
if (ret) {
cout << "找到了" << endl;
} else {
cout << "没找到" << endl;
}
//set关联式容器,元素自动排序,有序序列, 3 8 13
myset.insert(3); myset.insert(13); myset.insert(8);
for_each(myset.begin(), myset.end(), [](int val){cout << val << endl;});
//binary_search在有序容器中使用
ret = binary_search(myset.begin(), myset.end(), 8); //找到了
if (ret) {
cout << "找到了" << endl;
} else {
cout << "没找到" << endl;
}
}
(5) count
/*
count算法 统计元素出现次数
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param 要查找的元素
@return int返回元素个数
count(iterator beg, iterator end, value);
*/
(6) count_if
/*
count算法 统计元素出现次数
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param callback 回调函数或者谓词
@return int返回元素个数
count_if(iterator beg, iterator end, _callback);
*/
示例代码:
class myGreater:public binary_function<int, int, bool>
{
public:
bool operator()(int val, int compareVal) const {
return val > compareVal;
}
};
void test() {
vector<int>v; int num;
for(int i = 0; i < 10; i++) v.push_back(i+1);
//count
num = count(v.begin(), v.end(), 5);
cout << "找到5的个数为:" << num << endl; //1
//count_if
num = count_if(v.begin(), v.end(), bind2nd(myGreater(), 5));
cout << "找到大于5的个数为:" << num << endl; //5
}
4.5.3 排序算法
(1) sort
/*
sort算法 容器元素排序
@param beg 容器1开始迭代器
@param end 容器1结束迭代器
@param _callback 回调函数或者谓词(返回bool类型的函数对象)
sort(iterator beg, iterator end, _callback)
*/
(2) random_shuffle
/*
random_shuffle算法 对指定范围内的元素随机调整次序
@param beg 容器开始迭代器
@param end 容器结束迭代器
random_shuffle(iterator beg, iterator end)
*/
(3) reverse
/*
reverse算法 反转指定范围的元素
@param beg 容器开始迭代器
@param end 容器结束迭代器
reverse(iterator beg, iterator end)
*/
示例代码:
void test() {
vector<int>v;
for(int i = 0; i < 5; i++) v.push_back(i+1);
v.push_back(0);
// 1 2 3 4 5 0
for_each(v.begin(), v.end(), [](int v){ cout << v << endl; });
//sort默认从小到大排序 0 1 2 3 4 5
sort(v.begin(), v.end());
for_each(v.begin(), v.end(), [](int v){ cout << v << endl; });
//reverse 反转排序 5 4 3 2 1 0
reverse(v.begin(), v.end());
for_each(v.begin(), v.end(), [](int v){ cout << v << endl; });
//random_shuffle随机排序,最好配合srand,生成随机种子,这样每次结果才能不同 4 1 3 2 0 5
srand((unsigned int)time(NULL));
random_shuffle(v.begin(), v.end());
for_each(v.begin(), v.end(), [](int v){ cout << v << endl; });
}
4.5.4 拷贝和替换算法
(1) merge
/*
merge算法 容器元素合并,并存储到另一容器中。这两个容器必须是有序的,并且顺序是相同的
(都是升序或都是降序)。
@param beg1 容器1开始迭代器
@param end1 容器1结束迭代器
@param beg2 容器2开始迭代器
@param end2 容器2结束迭代器
@param dest 目标容器开始迭代器
@目标容器必须自己指定内存空间
@目标容器元素会自动排序
merge(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest)
*/
示例代码:
void test() {
vector<int>v1, v2, v3, v4, vTarget; int num;
//1.无序序列无法使用merge
v1.push_back(33); v1.push_back(3); v1.push_back(5);
v2.push_back(13); v2.push_back(3); v2.push_back(25);
//2.需要自己分配内存空间
vTarget.resize(v1.size() + v2.size());
//merge(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
//排序变为有序序列,使用merge
sort(v1.begin(), v1.end()); sort(v2.begin(), v2.end());
merge(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
//3. 目标容器会自动排序, 3 3 5 13 25 33
for_each(vTarget.begin(), vTarget.end(), [](int val){cout << val << endl;});
//有序序列才可以使用merge
for(int i = 0; i < 10; i++) {
v3.push_back(i+1); v4.push_back(i+1+100);
}
vTarget.resize(v3.size() + v4.size());
merge(v3.begin(), v3.end(), v4.begin(), v4.end(), vTarget.begin());
for_each(vTarget.begin(), vTarget.end(), [](int val){cout << val << endl;});
}
(2) transform
transform搬运到的目标容器,需我们自己显示分配内存,而且只能用resize,不能用reserver,reserve可以和push_back搭配使用,但不能和transform一起使用。
/*
transform算法 将指定容器区间元素搬运到另一容器中
注意 : transform 不会给目标容器分配内存,所以需要我们提前分配好内存
@param beg1 源容器开始迭代器
@param end1 源容器结束迭代器
@param beg2 目标容器开始迭代器
@param _cakkback 回调函数或者函数对象
@return 返回目标容器迭代器
transform(iterator beg1, iterator end1, iterator beg2, _callbakc)
template<class _InIt, class _OutIt, class _Fn1> inline
_OutIt _Transform(_InIt _First, _InIt _Last,_OutIt _Dest, _Fn1 _Func)
{
for (; _First != _Last; ++_First, ++_Dest)
*_Dest = _Func(*_First);
return (_Dest);
}
template<class _InIt1,class _InIt2,class _OutIt,class _Fn2> inline
_OutIt _Transform(_InIt1 _First1, _InIt1 _Last1,_InIt2 _First2, _OutIt _Dest, _Fn2 _Func)
{
for (; _First1 != _Last1; ++_First1, ++_First2, ++_Dest)
*_Dest = _Func(*_First1, *_First2);
return (_Dest);
}
*/
transform用法示例:
class TransForm
{
public:
int operator()(int val) { return val + 10; }
};
void test04()
{
vector<int>v; //原容器 vector<int>vTarget; //目标容器
for (int i = 0; i < 10; i++) { v.push_back(i); }
vTarget.resize(v.size());
transform(v.begin(), v.end(), vTarget.begin(), TransForm());
for_each(vTarget.begin(), vTarget.end(), [](int val){ cout << val << " "; });
}
//transform 第二种用法 将两个容器数据相加搬运到目标容器
class TransForm2
{
public:
int operator()(int val ,int val2) { return val + val2; }
};
void test05()
{
vector<int>v1, v2, vTarget; //目标容器
for (int i = 0; i < 10;i++) {
v1.push_back(100 + i); v2.push_back(200 + i);
}
vTarget.resize(v1.size());
transform(v1.begin(), v1.end(), v2.begin(), vTarget.begin(), TransForm2());
for_each(vTarget.begin(), vTarget.end(), [](int val){ cout << val << " "; });
}
(3) copy
/*
copy算法 将容器内指定范围的元素拷贝到另一容器中
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param dest 目标起始迭代器
@目标容器需自己申请内存空间resize
copy(iterator beg, iterator end, iterator dest)
*/
(4) replace
/*
replace算法 将容器内指定范围的旧元素修改为新元素
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param oldvalue 旧元素
@param oldvalue 新元素
replace(iterator beg, iterator end, oldvalue, newvalue)
*/
(5) replace_if
/*
replace_if算法 将容器内指定范围满足条件的元素替换为新元素
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param callback函数回调或者谓词(返回Bool类型的函数对象)
@param oldvalue 新元素
replace_if(iterator beg, iterator end, _callback, newvalue)
*/
(6) swap
/*
swap算法 互换两个容器的元素
@param c1容器1
@param c2容器2
swap(container c1, container c2)
*/
示例代码:
void test() {
vector<int>v, vTarget;
for(int i = 0; i < 5; i++) v.push_back(i+1); v.push_back(0);
//copy 拷贝
vTarget.resize(v.size());
copy(v.begin(), v.end(), vTarget.begin());
//新方法,打印容器中元素copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
//使用ostream_iterator要包含头#include <iterator>
copy(vTarget.begin(), vTarget.end(), ostream_iterator<int>(cout, " "));
cout << endl;
//replace元素替换 0替换为88
replace(vTarget.begin(), vTarget.end(), 0, 88);
copy(vTarget.begin(), vTarget.end(), ostream_iterator<int>(cout, " "));
cout << endl;
//replace将满足条件的元素替换为指定元素 将大于3的替换为0
replace_if(vTarget.begin(), vTarget.end(), bind2nd(greater<int>(), 3), 0);
copy(vTarget.begin(), vTarget.end(), ostream_iterator<int>(cout, " "));
cout << endl;
}
(7) fill
/*
fill算法 向容器中添加元素
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param value 填充/替换元素
fill(iterator beg, iterator end, value)
*/
示例代码:
#include <iterator>
void test() {
vector<int>v, vTarget;
v.resize(5);
fill(v.begin(), v.end(), 8);
// 8 8 8 8 8
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
cout << endl;
}
4.5.5 算数算法
(1) accumulate
/*
accumulate算法 计算容器元素累计总和
@需要包含头文件numeric numeric [nu:'merɪk] adj: 数字的,数值的
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param value第三个参数 起始累加值
@返回值,累加值
accumulate(iterator beg, iterator end, value)
*/
示例代码:
#include <numeric>
void test() {
vector<int>v; int sum;
v.push_back(1); v.push_back(2); v.push_back(3);
sum = accumulate(v.begin(), v.end(), 0);
cout << "总和是:" << sum << endl; //6
sum = accumulate(v.begin(), v.end(), 100);
cout << "总和是:" << sum << endl; //106
}
(2) 集合算法
目标容器必须自己手动分配空间
<1> 交集 set_intersection
set_intersection算法 求两个set集合的交集
注意:两个集合必须是有序序列
@param beg1 容器1开始迭代器
@param end1 容器1结束迭代器
@param beg2 容器2开始迭代器
@param end2 容器2结束迭代器
@param dest 目标容器开始迭代器
@return 目标容器的最后一个元素的迭代器地址
set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest)
<2> 并集 set_union
set_union算法 求两个set集合的并集
注意:两个集合必须是有序序列
@param beg1 容器1开始迭代器
@param end1 容器1结束迭代器
@param beg2 容器2开始迭代器
@param end2 容器2结束迭代器
@param dest 目标容器开始迭代器
@return 目标容器的最后一个元素的迭代器地址
set_union(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest)
<3>差集 set_difference
set_difference算法 求两个set集合的差集
注意:两个集合必须是有序序列
@param beg1 容器1开始迭代器
@param end1 容器1结束迭代器
@param beg2 容器2开始迭代器
@param end2 容器2结束迭代器
@param dest 目标容器开始迭代器
@return 目标容器的最后一个元素的迭代器地址
set_difference(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest)
示例代码:
#include <iterator>
void test() {
vector<int>v1, v2, vTarget1, vTarget2, vTarget3, vTarget4;
vector<int>::iterator targetEnd;
for (int i = 0; i < 6; i++) {
v1.push_back(i + 1); v2.push_back(i + 5);
}
//v1 1 2 3 4 5 6
copy(v1.begin(), v1.end(), ostream_iterator<int>(cout, " ")); cout << endl;
//v2 5 6 7 8 9 10
for_each(v2.begin(), v2.end(), [](int val){cout << val << " ";}); cout << endl;
//1.set_intersection 求交集 5 6
//目标容器分配空间
vTarget1.resize(min(v1.size(), v2.size()));
//返回值为目标容器最后一个元素迭代器地址
targetEnd = set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget1.begin());
copy(vTarget1.begin(), targetEnd, ostream_iterator<int>(cout, " ")); cout << endl;
//2.并集set_union 1 2 3 4 5 6 7 8 9 10
vTarget2.resize(v1.size() + v2.size());
targetEnd = set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget2.begin());
copy(vTarget2.begin(), targetEnd, ostream_iterator<int>(cout, " ")); cout << endl;
//3.差集set_difference
//v1差v2 1 2 3 4
vTarget3.resize(v1.size());
targetEnd = set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget3.begin());
copy(vTarget3.begin(), targetEnd, ostream_iterator<int>(cout, " ")); cout << endl;
//v2差v1 7 8 9 10
vTarget4.resize(v2.size());
targetEnd = set_difference(v2.begin(), v2.end(), v1.begin(), v1.end(), vTarget4.begin());
copy(vTarget4.begin(), targetEnd, ostream_iterator<int>(cout, " ")); cout << endl;
}
5.STL综合案例(学校演讲比赛)
演讲比赛案例
比赛规则:
• 某市举行一场演讲比赛( speech_contest ),共有24个人参加。比赛共三轮,前两轮为淘汰赛,第三轮为决赛。
• 比赛方式:分组比赛,每组6个人;选手每次要随机分组,进行比赛;
第一轮分为4个小组,每组6个人。比如编号为: 100-123. 整体进行抽签(draw)后顺序演讲。当小组演讲完后,淘汰组内排名最后的三个选手,然后继续下一个小组的比赛。
第二轮分为2个小组,每组6人。比赛完毕,淘汰组内排名最后的三个选手,然后继续下一个小组的比赛。
第三轮只剩下1组6个人,本轮为决赛,选出前三名。
• 比赛评分:10个评委打分,去除最低、最高分,求平均分每个选手演讲完由10个评委分别打分。该选手的最终得分是去掉一个最高分和一个最低分,求得剩下的8个成绩的平均分。选手的名次按得分降序排列。
用STL编程,求解这个问题
1) 请打印出所有选手的名字与参赛号,并以参赛号的升序排列。
2) 打印每一轮比赛后,小组比赛成绩和小组晋级名单
需求分析:
1) 产生选手 ( ABCDEFGHIJKLMNOPQRSTUVWX ) 姓名、得分;选手编号
2) 第1轮 选手抽签 选手比赛 查看比赛结果
3) 第2轮 选手抽签 选手比赛 查看比赛结果
4) 第3轮 选手抽签 选手比赛 查看比赛结果
实现思路:
需要把选手信息、选手得分信息、选手比赛抽签信息、选手的晋级信息保存在容器中,需要涉及到各个容器的选型。
选手可以设计一个类Speaker(姓名和得分)
所有选手的编号可以单独放在一个vector容器中,做抽签用
所有选手编号和选手信息,可以放在容器内:map<int, Speaker>
所有选手的编号名单,可以放在容器:vecter<int> v1中
第1轮晋级编号名单,可以放在容器vecter<int> v2中
第2轮晋级编号名单,可以放在容器vecter<int> v3中
第3轮前三名名单,可以放在容器vecter<int> v4中
每个小组的比赛得分信息,按照从大到小的顺序放在multimap<成绩, 编号, greater<int>>中
每个选手的得分,可以放在容器deque<int> dscore; 方便去除最低最高分.