学习C++——泛型算法

1、概述

标准库定义了一组泛型算法,它们实现了一些经典算法的公共接口,还可以适用于不同类型的元素和多种容器类型。
大部分算法定义在头文件 algorithm中。标准库还在头文件 numeric中定义了一组数值泛型算法。
下面的例子是调用标准库算法find,来实现查找操作:
#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
	using namespace std;
	int val;
	vector<int> vec;
	cout << "Input the value of vec :";
	for(int i = 0; i<5; ++i)//输入vector的值
	{
		cin >> val;
		vec.push_back(val);
	}
	cout << "Input the value to find: ";
	cin >> val;//输入要查找的值
	auto result = find(vec.cbegin(), vec.cend(), val);//查找val,用标准库算法find。
	cout << "The result " << val 
		<< (result == vec.cend() ? " is not present" : " is present") << endl;
	cout << "\nInput the value to find: ";
	cin >> val;//输入要查找的值
    result = find(vec.cbegin(), vec.cend(), val);//查找val,用标准库算法find。
	cout << "The result " << val 
		<< (result == vec.cend() ? " is not present" : " is present") << endl;

	cin.get();
	cin.get();
	return 0;
}




//在list中查找一个给定值
string val = "value";
auto result = find(lst.cbegin(), lst.cend(), val);

//在数组中查找一个给定值
int ia[] = {2,3,45,54};
int val = 45;
int *result = find(begin(ia), end(ia), val);

count算法:

#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
	using namespace std;

	vector<int> vec;
	int val, n;
	cout << "Input the number of n: ";//输入vector的大小
	cin >> n;
	cout << "Input the value of vec:";//输入vector中的值
	for(int i=0; i<n; ++i)
	{
		cin >> val;
		vec.push_back(val);
	}
	cout << "Input the value to count:";//输入要计数的值
	cin >> val;
	auto result = count(vec.cbegin(), vec.cend(), val);
	/*
		count函数返回给定值在序列中出现的次数;
	*/
	cout << "There are " << result << " is equal to the value of the vector.";

	cin.get();
	cin.get();
	return 0;
}


2、初识泛型算法

2.1、只读算法

find和count都是只读算法。
  • 算法和元素类型:
accumulate定义在头文件numeric中。
int sum = accumulate(vec.cbegin(), vec.end(), 0);//将sum设置为vec中元素的和,和的初值被设置为0;
string sum = accumulate(v.cbegin(), v.cend(), string(""));//将vector中的字符串全部连接起来。
  • 操作两个序列的算法
equal算法来确保两个序列中是否保存了相同的值,如果两个序列对应的元素都相等,则返回true,否则返回false。
equal(v.cbegin(), v.cend(), v2.cbegin());//前两个参数表示第一个序列的元素范围,第三个参数表示第二个序列的首元素

备注:equal假设第二个序列至少和第一个序列一样长。

例子:
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>

int main()
{
	using namespace std;

	vector<int> vec;
	int val, n;
	cout << "Input the number of n: ";//输入vector的大小
	cin >> n;
	cout << "Input the value of vec:";//输入vector中的值
	for(int i=0; i<n; ++i)
	{
		cin >> val;
		vec.push_back(val);
	}
	int sum = accumulate(vec.cbegin(), vec.cend(), 0);//vector中元素的和为sum 
	cout << "sum = " << sum << endl;

	cin.get();
	cin.get();
	return 0;
}




2.2、写容器元素的算法

由于算法不会执行容器操作,因此他们自身不可能改变容器的大小。所以要确保容器的大小要至少等于我们要写入的元素数目;
fill(vec.begin(), vec.end(), 0);//将每一个元素设置为0
fill(vec.begin(), vec.begin()+vec.size()/2, 10);//将容器的一个子序列设置为10

  • fill_n函数接受一个单迭代器、一个计数值和一个值,它将给定值赋予迭代器指向的元素开始的指定个元素。

fill_n(vec.begin(), vec.size(), 0);//将所有元素设置为0
fill_n(dest, n, val);//将从dest开始的n个元素的值设置为val,但是要确保dest之后有n个元素。

  • back_inserter
一种保证算法有足够的元素空间来容纳输出数据的方法是使用插入迭代器(insert   iterator)。插入迭代器是一种向容器中添加元素的迭代器。
定义在头文件iterator中。
vector<int> vec;//空向量
fill_n(vec.begin(), 10, 0);//错误,修改10个不存在的元素
//但是下面的语句正确
//back_inserter创建一个插入迭代器,可用来向vec添加元素。
fill_n(back_inserter(vec), 10, 0);//添加10个元素到vec。
  • 拷贝算法(copy)
此算法接受三个迭代器,前两个表示一个输入范围,第三个表示目的序列的起始位置。此算法将输入范围内的元素拷贝到目的序列中。
int a1[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int a2[sizeof(a1) / sizeof(*a1)];//保证a2和a1大小相同
auto ret = copy(begin(a1), emd(a1), a2);//把a1的内容拷贝到a2中,ret指向拷贝到a2的尾元素之后的位置
  • 替换指定元素(replace, replace_copy)
replace算法读入一个序列,并将其中所有等于给定值的元素都改为另一个值。此算法接受四个参数:前两个是迭代器,表示输入序列,后两个一个是要搜索的值,另一个是新值。
replace(ilst.begin(), ilst.end(), 0, 42);//将所有值为0的元素改为42。此调用将原序列的值改变了。
//为了不改变原序列的值,采用函数replace_copy
replace_copy(ilst.cbegin(), ilst.cend(), back_inserter(ivec), 0, 42);
//调用后,ilst保持不变,ivec中包含一份拷贝,等于ilst中值为0的元素变为了42之后的序列

2.3、重排容器元素的算法

  • sort排序,由小到大
  • unique重排输入序列,将相邻的重复项删除
例子:

/*
	函数功能:消除重复单词
*/
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

using namespace std;

void elimDups(vector<string> &words);

int main()
{
	
	vector<string> words;
	string val;
	cout << "Input the words: ";

	while(cin >> val)//用循环,输入字符串
	{
		words.push_back(val);
	}
	elimDups(words);//调用函数,排序,删除

	cout << "The output is: ";//输出排序删除之后的单词
	for(auto beg = words.begin(), end = words.end(); beg != end; ++beg)
		cout << *beg << " ";

	while(1);
	return 0;
}
void elimDups(vector<string> &words)
{
	sort(words.begin(), words.end());//按字典序排序
	//uinque重排输入范围,使得每个单词只出现一次
	//排列在范围的前部,返回指向不重复区域之后一个位置的迭代器
	auto end_unique = unique(words.begin(), words.end());
	//使用向量操作erase删除重复单词
	words.erase(end_unique, words.end());
}



备注:
  1. words使用unique之后,大小并未改变,还是7个元素。但是这些元素的顺序被改变了-相邻重复元素被“删除”了。unique并不是真的删除任何元素,它只是覆盖相邻的重复元素,使得不重复元素出现在序列的开始部分。
  2. unique返回的迭代器指向最后一个不重复元素之后的位置。此位置之后的元素仍然存在,但我们不知道它们的值是什么。
  3. 最后是使用erase来删除那些重复的元素。

3、定制操作

 很多算法都会比较输入序列中的元素。默认情况下,这类算法使用元素类型的<或==运算符完成比较。标准库还胃这些算法定义了额外的版本,允许我们提供自己定义的操作来代替默认运算符。
例如:使用sort算法默认使用<运算符。如果我们想使用>,这时就需要重载sort的默认行为。

  • 向算法传递函数
如果希望在调用elimDups排序并且删除重复之后,还想要再将剩下的单词按照其长度排序(由小到大)。
需要重载sort函数:
bool isShorter(const string &s1, const string &s2)
{
	return s1.size() < s2.size();
}

sort(words.begin(), words.end(), isShorter);//按长度由短至长排序
  • 排序算法
我们将words按大小重排的同时,还希望具有相同长度的元素按字典序排列。为了保持相同长度的单词按字典序排列,可以使用stable_sort算法。这种算法维持相等元素的原有顺序。
elimDups(words);
stable_sort(words.begin(), words.end(), isShorter);
for(const auto &s : words)
	cout << s << " ";

练习:

/*
	函数功能:将单词按从小到大的顺序排列,并删除重复的单词;
			  再按单词的长度由短到长排列。
	算法函数:stable_sort();sort();
*/
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

using namespace std;

void elimDups(vector<string> &words);
bool isShorter(const string &s1, const string &s2);
int main()
{
	
	vector<string> words;
	string val;
	cout << "Input the words: ";

	while(cin >> val)//用循环,输入字符串
	{
		words.push_back(val);
	}
	elimDups(words);//调用函数,排序,删除

	stable_sort(words.begin(), words.end(), isShorter);
	cout << "The output is: ";//输出排序删除之后的单词
	for(auto beg = words.begin(), end = words.end(); beg != end; ++beg)
		cout << *beg << " ";
	
	while(1);
	return 0;
}
void elimDups(vector<string> &words)
{
	sort(words.begin(), words.end());//按字典序排序
	//uinque重排输入范围,使得每个单词只出现一次
	//排列在范围的前部,返回指向不重复区域之后一个位置的迭代器
	auto end_unique = unique(words.begin(), words.end());
	//使用向量操作erase删除重复单词
	words.erase(end_unique, words.end());
}

bool isShorter(const string &s1, const string &s2)
{
	return s1.size() < s2.size();
}

  • lambda表达式

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值