C++ STL常用算法

常用遍历算法

以下算法都在头文件<algorithm>中

  • for_each 实现遍历容器
for_each(iterator beg, iterator end, _func);\\beg 开始迭代器	end 结束迭代器  _func 函数或者函数对象

_func传入普通函数

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);\\遍历输出v容器中的元素
}

运行结果

​ 2 3 43 324 234 123 2345 435 34

_func传入仿函数

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());\\遍历输出v容器中的元素
}

运行结果

2 3 43 324 234 123 2345 435 34

  • transform 搬运容器到另一个容器
transform(iterator beg1, iterator end1, iterator beg2, _func);\\beg1 源容器开始迭代器	end1 源容器结束迭代器 beg2 目标容器开始迭代器 _func 函数或者函数对象
class Trans {//仿函数实现将数据元素+10操作
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());//为vTraget容器开辟与v容器等大的空间,否则程序运行会被中止
	transform(v.begin(), v.end(),vTarget.begin(), Trans());//将v容器中的数据+10后搬运到vTarget中
	for_each(vTarget.begin(), vTarget.end(), printFunctor());//打印vTarget容器
}

运行结果

11 12 13 14 15 16 17 18 19

常用查找算法

  • find 查找指定元素,找到返回指定元素的迭代器,否则返回end()
find(iterator beg.iterator end,value)//value为查找的元素
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函数自然也不会执行成功,该如何修改程序呢?

首先把自定义数据类型与重载函数设计好

class Person {
public:
	string p_name;
	int p_age;
	Person(string name, int age) {
		this->p_age = age;
		this->p_name = name;
	}
};

接下来就以查找成功的案例演示

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);//查找p1,it返回查找指定值的迭代器
	if (it != v.end()) {
		cout << "找着" << it->p_name << "了  " <<"年龄:"<<it->p_age<<endl;
	}
}

运行结果

找着吴京了 年龄:45

  • find_if 按条件查找元素
find_if(iterator beg,iterator end, _Pred);//_Pred 函数或者谓词

以在1-10数值查找大于5的数为例,来看一看 find_if 的效果

写一个判定大于5的谓词

class GT5 {
public:
	bool operator()(int val) {
		return val>5;
	}
};

接下来展示一下 find_if 的效果

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 查找相邻重复元素
adjacent_find(iterator beg, iterator end);

很简单,返回第一个相邻的重复元素

对于自定义的数据类型需要单独写函数或者仿函数

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());//查找p1,it返回查找指定值的迭代器
	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

二分查找指定元素是否存在,返回的是布尔类型

适用于有序数列

bool binary_search(iterator beg, iterator end, value);
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

统计元素个数

count(iterator beg,iterator end,value);

统计自定义数据类型要实现==的重载

  • count_if

按条件统计元素个数

count_if(iterator beg, iterator end, _Pred);

方法同样是分内建数据类型和自定义数据类型两种实现方式,归根到底的区别在于谓词的设计上的不同

class FindByAge {
public:
	bool operator()(const Person &P) {
		return P.p_age ==40;//查找年龄等于40的Person数据
	}
};
class GT5 {
public:
	bool operator()(int val) {
		return val > 5;//查找值大于5的数据
	}
};

常见排序算法

  • sort

容器内数据排序

sort(iterator beg, iterator end, _Pred);

将容器内的数据逆序案例:

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

洗牌 指定范围内的元素随机调整次序, 使用时加随机数种子,使数据更有随机性

random_shuffle(iterator beg, iterator end);
void showPerson(const Person& p) {
	cout << "   " << p.p_name << " : " << p.p_age;

}//打印输出Person
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

合并两个容器,并存储到另一个容器,实际上就是归并排序

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());//为v3分配容量
	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

反转

reverse(iterator beg, iterator end);

常用拷贝和替换算法

  • copy
copy(iterator beg, iterator end,iterator dest)//dest目标容器起始迭代器

下面的案例是拷贝一个自定义数据类型容器的案例

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());//为v1开辟与v相等的空间
	vector<Person>::iterator it;//定义一个迭代器,此时Person类一定要有默认构造函数
	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

将容器内指定范围的旧元素修改为新元素

replace(iterator beg, iterator end, oldvalue, newvalue)

下列案例将吴京的数据替换成郭帆的数据

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

将区间内满足条件的元素替换成指定元素

replace_if(iterator beg, iterator end, _pred, newvalue);

将年龄大于40人的数据都替换成郭帆

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

互换两个容器的元素

swap(container c1, container c2);//c1, c2两个同种类型的容器

算术生成算法

#include <numeric>

  • accumulate
accumulate(iterator beg,iterator end, value);//计算容器元素累计总和 value起始值
  • fill
fill (iterator beg.iterator end, value);//像容器填充value

集合算法

  • 交集 set_intersection

    set_intersection(iterator beg1, iterator end1,iterator beg2, iterator end2,iterator dest)//dest目标容器起始迭代器
    
  • 并集 set_union

  • 差集 set_difference

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值