泛型容器

#include<iostream>
#include<algorithm>
#include<numeric>
#include<vector>
#include<string>
#include<queue>
#include <functional>
#include<list>
#include<fstream>

using namespace std;
void test() {
	int val = 42;
	vector<int>vec;
	//如果在vec中找到想要的元素,返回结果指向他,否则返回结果为vec.cend();
	auto result = find(vec.cbegin(), vec.cend(), val);
	string val = "a value";
	vector<string>lst;
	auto result = find(lst.cbegin(), lst.cend(), val);
	int ia[] = { 23, 21, 46, 89, 90 };
	int val = 83;
	int* result = find(begin(ia), end(ia), val);
	auto result = find(ia + 1, ia + 4, val);


	//迭代器算法不依赖与容器但是算法依赖于元素类型的操作,算法永远不会改变底层容器的大小

	//泛型算法
	//只读算法
	//一些算法只会读取其输入范围的元素,而从不改变元素
	vector<int>vec;
	int sum = accumulate(vec.cbegin(), vec.cend(), 0);
	vector<string>s;
	string sum = accumulate(s.cbegin(), s.cend(), string(""));
	//错误 :const char* 上没有定义+运算符
	string sum = accumulate(s.cbegin(), s.cend(), "");

	//操作两个序列的算法
	vector<int>roster1, vector<int>roster2;
	equal(roster1.cbegin(), roster1.cend(), roster2.cbegin()); //用于确定两个序列是否具有相同的值
	//写容器元素
	fill(vec.begin(), vec.end(), 0); // 将每个元素重置为0
	fill(vec.begin(), vec.end() + vec.size() / 2, 10);

	//算法不检查写操作
	vector<int>vec;
	fill_n(vec.begin(), vec.size(), 0); //将所有元素置于0
	//新手容易犯的错误
	fill_n(vec.begin(), 10, 0); //修改vec中10个不存在的元素,这个 是未定义的

	//back_inserter
	/*
	一种保证算法有足够空间来容纳输出数据的方法是使用插入迭代器,通常情况下,当我们使用一个迭代器对容器元素赋值时,
	值被赋予迭代器所指向的元素,而当我们通过插入迭代器赋值的时候,一个与赋值号右侧值相等的元素被添加到容器
	back_inserter接受一个指向容器的引用,返回一个与该容器绑定的迭代器当我们通过此迭代器赋值时,赋值运算符会调用
	push_back将一个具有给定值得元素添加到容器中
	*/
	vector<int>vec;
	auto it = back_inserter(vec);
	*it = 42;
	//我们通常使用back_inserter来创建一个迭代器
	vector<int>vec;
	fill_n(back_inserter(vec), 10, 0); //添加10个元素到vec

	//拷贝算法
	int a1[] = { 0, 1, 2, 3, 4,5, 6, 7 };
	int a2[sizeof(a1) / sizeof(*a1)];
	auto ret = copy(begin(a1), end(a1), a2); //把a1的内容拷贝给a2
	//copy返回的是其目的位置迭代器(递增后)的值

	//replace
	vector<int>ilst;
	replace(ilst.begin(), ilst.end(), 0, 42);
	//如果我们希望保持原来的序列不变
	vector<int>ivec;
	replace_copy(ilst.cbegin(), ilst.cend(), back_inserter(ivec), 0, 42); //ivec包含ilst的一份拷贝


	

}
//重排容器的算法
void elimDups(vector<string>& words) {
	sort(words.begin(), words.end());
	auto end_unique = unique(words.begin(), words.end()); 
	/*
	unique并不是真的删除元素,他只是覆盖相邻的元素,使得不重复元素出现在序列的开始部分,unique的迭代器
	指向最后一个不重复元素之后的位置,此位置之后的元素任然存在,但是我们不知道他的值
	标准库算法对迭代器而不是容器进行操作,因此算法不能直接添加或删除元素
	*/
	words.erase(end_unique, words.end());
}


//定制操作
//向算法传递函数-谓词
bool isShorter(const string& s1, const string& s2) {
	return s1.size() < s2.size();
}
void test02() {
	vector<string>words;
	sort(words.begin(), words.end(), isShorter);
}

//lambda
/*
一个lambda表达式表示一个可调用的代码单元,可以理解为未命名的内联函数,一个lambda具有返回类型,一个参数列表,一个函数体
但是与函数不同,lambda可以定义在函数内部
*/
auto f = [] {return 42; };
void test03() {
	cout << f() << endl;
	auto a = [](const string& a, const string& b) {
		return a.size() < b.size();
	};
	//按照长度排序,长度相同的单词维持字典序
	vector<string>words;
	stable_sort(words.begin(), words.end(), [](const string& a, const string& b) {return a.size() < b.size(); });

	//使用捕获列表
	int sz;
	[sz](const string& a, const string& b) {return a.size() < b.size(); };

	//调用find_if
	//获取一个迭代器,指向第一个满足size() >= sz的元素
	auto wc = find_if(words.begin(), words.end(), [sz](const string& a, const string& b) {return a.size() < b.size(); });


	//for_each算法

	for_each(wc, words.end(), [](const string& s) {cout << s << " "; });//捕获列表只用于局部非static变量,lambda可以直接使用局部static变量和他所在函数之外声明的名字
	
}


//lambda的值捕获和引用捕获
void fun1() {
	size_t v1 = 42;
	auto f = [v1] {return v1; };
	v1 = 0;
	auto j = f(); // j为42,f保存我们创建他时v1的拷贝
}
void fun2() {
	size_t v1 = 42;
	auto f2 = [&v1] {return v1; };
	v1 = 0;
	auto j = f2(); // j为0
}
//引用捕获有时是必要的,我们可能希望biggies函数接受一个ostream的引用,用来输出数据
vector<string>words;
void biggies(vector<string>& word, vector<string>::size_type sz, ostream& os = cout, char c = ' ') {
	for_each(words.begin(), words.end(), [&os, c](const string& s) {os << s << s; });
}

//隐式捕获
int sz;
//sz为隐式捕获,值捕获方式
auto wc = find_if(words.begin(), words.end(), [=](const string& s) {return s.size() >= sz; });
//如果我们希望对一部分变脸采用值捕获,对其他变量采用引用捕获,可以混合使用隐式捕获和显示捕获
void biggies(vector<string>& words, vector<string>::size_type sz, ostream &os = cout, char c = ' ') {
	
	//os隐式捕获,引用捕获方式,c为显示捕获,值捕获方式
	for_each(words.begin(), words.end(), [&, c](const string& s) {os << s << c; });
	//os显示捕获,引用捕获方式,c隐式捕获,值捕获方式
	for_each(words.begin(), words.end(), [=, &os](const string& s) {os << s << s; });
}


//可变的lambda
/*
默认情况下,对于一个值被拷贝的变量,lambda不会改变其值,如果我们希望改变一个被捕获的变量的值,就必须在参数列表上
加上关键词mutable
*/
void fun3() {
	size_t v1 = 42;
	auto f = [v1]()mutable {return ++v1; };
	v1 = 0;
	auto j = f();
}
//一个引用捕获的变量是否可以修改依赖于此引用指向的是一个const类型还是非const类型
void fun4() {
	size_t v1 = 42;
	auto f2 = [&v1] {return ++v1; };
	v1 = 0;
	auto j = f2(); //j为1;
}

//指定lambda的返回类型
vector<int>vi;
void test05() {
	transform(vi.begin(), vi.end(), vi.begin(), [](int i) {return i < 0 ? -i : i; });
	//前两个迭代器表示输入序列,第三个迭代器表示目的位置
	//但是如果将程序改写为如下的if语句,就会产生编译错误
	transform(vi.begin(), vi.end(), vi.begin(), [](int i) {if (i < 0)return -i; else return i; });
	//编译器推荐这个版本的lambda返回类型为void,但是他返回了一个int值,但我们需要为一个lambda定义返回类型时,必须使用尾置返回类型
	transform(vi.begin(), vi.end(), vi.begin(), [](int i)->int {if (i < 0)return -i; else return i; });
}

//参数绑定
bool check_size(const string& s, string::size_type sz) {
	return s.size() >= sz;
}
//标准库bind函数
//绑定check_sizez的sz函数
void test06() {
	auto check6 = bind(check_size, placeholders::_1, 6);
	string s = "hello";
	bool b1 = check6(s);
	auto wc = find_if(words.begin(), words.end(), bind(check_size, placeholders::_1, sz));

}
//使用placeholders
using std::placeholders::_1;


/*bind的参数
auto g = bind(f, a, b, _2, c, _1);
f是一个可调用对象它有五个参数,上面的操作将生成一个新的可调用对象,它有两个参数,分别用那两个占位符表示
这个新的可调用对象将自己的参数作为第三个和第五个参数传递给f,f的第一个,第二个,第四个参数分别被绑定在给定的值a,b,c上
g(_1, _2)
映射f(a, b, _2, c, _1)
*/

//使用bind重排参数顺序
static void test07() {
	sort(words.begin(), words.end(), isShorter);
	sort(words.begin(), words.end(), bind(isShorter, placeholders::_2, _1));
	//第一个调用中sort需要比较两个元素a和b时,它会调用isShorter(a, b)
	//第二个调用中,传递的参数被交换过来了,因此,sort比较两个元素时,就好像调用isShorter(b, a)
}

//绑定引用参数
void test08(vector<string>& words, vector<string>::size_type sz, ostream& os = cout, char c = ' ') {
	for_each(words.begin(), words.end(), [&os, c](const string& s) {os << s << c; });
	for_each(words.begin(), words.end(), bind(print, os, _1, ' ')); //错误,不可以拷贝os
	/*
	原因在bing拷贝其参数,而我们不能拷贝一个ostream,如果我们希望传递给bind一个对象而又不拷贝它,就必须使用标准库ref函数
	*/
	for_each(words.begin(), words.end(), bind(print, ref(os), _1, ' '));
	
}
ostream& print(ostream& os, const string& s, char c) {
	return  os << s << c;
}
//可以代替上面那个函数


//插入迭代器
void test09() {
	list<int>lst = { 1, 2, 3, 4 };
	list<int>lst2, list<int>lis3;
	copy(lst.cbegin(), lst.cend(), front_inserter(lst2));
	copy(lst.cbegin(), lst.cend(), inserter(lis3, lis3.begin()));

}

//istream迭代器
//iostream_iterator
void test10() {
	vector<int>vec;
	istream_iterator<int>int_it(cin);
	istream_iterator<int>int_eof;
	ifstream in("afile");
	istream_iterator<string>str_it(in);
	istream_iterator<int>in_iter(cin);
	istream_iterator<int>eof;
	while (in_iter != eof) {
		vec.push_back(*in_iter++);
	}

	istream_iterator<int>in_iter(cin), eof;
	vector<int>vec(in_iter, eof);//从迭代器范围构造vec,这意味着元素范围是从关联的流中读取数据获得的,这个构造函数从cin中
	//读取数据,直到遇到文件尾部或者遇到一个不是int的数据为止

	//使用算法操作流迭代对象
	istream_iterator<int> in(cin), eof;
	cout << accumulate(in, eof, 0) << endl;

}
//ostream操作
void test11() {
	vector<int>vec;
	ostream_iterator<int>out_iter(cout, " ");
	for (auto e : vec) {
		*out_iter++ = e; //赋值语句实际将元素写到cout
		
	}
	cout << endl;
	//值得注意的是,当我们向out_iter赋值时,可以忽略解引用和递增运算
	for (auto e : vec) {
		out iter = e;
	}
	cout << endl;
	//可以调用copy来打印vec中的元素
	copy(vec.begin(), vec.end(), out_iter);
}


//反向迭代器
void test12() {
	vector<int>vec = { 0, 1, 2, 3, 4, 5, 6, 7 };
	for (auto r_iter = vec.crbegin(); r_iter != vec.crend(); ++r_iter)
		cout << *r_iter << endl;
	sort(vec.begin(), vec.end());
	sort(vec.rbegin(), vec.rend());//逆序排序
}

//反向迭代器在书上364页,不想敲了


//区别拷贝元素的版本和不拷贝的版本
void test13() {
	vector<int>vec = { 0, 1, 2, 3,4 };
	vector<int>dest(10);
	auto beg = vec.begin();
	auto end = vec.end();
	reverse(beg, end);
	reverse_copy(beg, end, dest);
	vector<int>v1 = { 1, 2, 3 };
	vector<int>v2;
	remove_if(vec.begin(), vec.end(), [](int i) {return i % 2; });
	remove_copy_if(v1.begin(), v1.end(), back_inserter(v2), [](int i) {return i % 2; });
}

//
int main() {
	return 0;
}
posted @ 2022-03-16 21:11  W-forever  阅读(50)  评论(0)    收藏  举报