c++ 4:STL算法

四. 常用算法

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; 方便去除最低最高分.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值