C++ 泛型算法


本文适合新手阅读,亦可所谓手册查阅

前言

泛型算法与容器无关。操作迭代器。
算法不会执行容器操作,算法本身并不改变容器大小,但是可以通过操纵insert, erase来改变容器。


泛型算法

只读

accumulate(c.begin(), c.end(), 初始加和数)
equal(c.cbegin(), c.edn(), c2.cbegin())

写容器

fill(c.begin(), c.end(), 0);               //将每个元素置为0
fill(c.begin(), c.begin()+c.size()/2, 10); //将容器的一个子序列设置为10

fill_n(dest, n, val);

back_inserter
有点像.push_back(val)
返回容器最后位置的迭代器

vector<int> vec;
fill_n(back_inserter(vec), 10, 0); //添加10个元素0到vec

拷贝算法

int a1[] = {0,1,2,3,4,5,6,7,8,9};
int a2[sizeof(a1) / sizeof(*a1)]; //a2与a1大小一样
auto res = std::copy(begin(a1), end(a1), a2);//返回a2拷贝赋值后的最后一个元素的后一位
//copy(开始位置,结束位置, 目的序列的起始位置)

//将[ )中的值所有0,替换为42
replace(ilst.begin(), ilst.end(), 0, 42);
replace_copy(ilst.begin(), ilst.end(), back_inserter(ivec), 0, 42);

排序

sort(迭代器1, 迭代器2) //完成sort后,容器有序
unique(迭代器1, 迭代器2)//重排范围,“消除”重复项,返回不重复范围最后位置的迭代器

标准库算法对迭代器而不是容器进行操作。因此,算法不能(直接)添加或删除元素。

void elimDups(vector<string> &words){
	sort(words.begin(), words.end());
	auto end_unique = unique(words.begin(), words.end());
	words.erase(end_unique, words.end());
}


定制操作

bool isShorter(const string &s1, const string &s2){
	return s1.size() < s2.size();
}
sort(words.begin(), words.end(), isShorter);
stable_sort(words.begin(), words.end(), isShorter);
partition(vec.begin(), vec.end(), isShorter);

lambda表达式

可将其理解为一个未命名的内联函数,可以定义在函数内部。
[ capture list ] ( parameter list ) -> return type { function body }
capture list (捕获列表)在lambda所在函数中定义的局部变量的列表(通常为空),捕获列表只用于局部非static变量,lambda可以直接使用局部static变量和在它所在函数之外声名的名字。

auto f = []{return 42;} ;  // ()->return type 和省略
cout << f() << endl; //print 42

必须使用位置返回。不能有默认参数。
find_if

auto wc = find_if(words.begin(), words.end(), 
				  [sz](const string &a){return a.size() >= sz;} );
auto count = words.end() - wc;

void biggies(vector<string>& words, vector<string>::size_type sz){
	elimDups(words); //将words按字典顺序排序,删除重复单词
	//按长度排序,长度相同的单词维持字典
	stable_sort(words.begin(), words.end(), 
				[](const string &a, const string &b){return a.size()<b.size();} );
	auto wc = find_if(words.begin(), words.end(), 
					  [sz](const string &a){return a.size()>=sz; });
	auto count = words.end() - wc;
	cout << count << " " << make_plural(count, "word", "s") << " of length "
		 << sz << " or longer " << endl;
	for_each(wc, words.end(), [](const string &s){cout << s << " ";} );
	cout << endl; 
}

lambda捕获和返回

值捕获的前提是变量可以拷贝。

// 值捕获
void fcn1(){
	auto v1 = 42;
	auto f = [v1]{return v1;};
	v1 = 0;
	auto j = f(); //j为42,f保存了我们创建它时v1的拷贝
}

//引用捕获
void fcn1(){
	auto v1 = 42;
	auto f = [&v1]{return v1;};
	v1 = 0;
	auto j = f(); //j为0,f保存了v1的引用,而非拷贝
}

//隐式捕获
wc = find_if(words.begin(), sords.end(), 
			[=]/*隐式值捕获*/(const string&s){return s.size()>=sz;} );
			[&]/*隐式引用捕获*/(const string&s){return s.size()>=sz;}
//只有这两种写法
[&, c]{os << s << c;} //
[=, &os]{os <<s<<c ;} //

在这里插入图片描述
可变lambda

void fcn3(){
	int v1 = 42;
	auto f = [v1]() mutable {return ++v1;};
	v1 = 0;
	auto j = f(); //j == 43
}
transform(vi.begin(), vi.end(), vi.begin()/*目的位置*/,
		  [](int i){return i < 0 ? -i : i;} );       // 正确lambda只有一条return语句,默认推断正确
		  [](int i){if(i<0)return -i;else return i;} // 错误,有多条语句默认推断void与实际不符
		  [](int i)->int{return i < 0 ? -i : i;}     // 正确

auto i = count_if(迭代器范围a, 迭代器范围b,谓词);//对输入范围中每个元素执行谓词操作,返回一个计数值,表示谓词有多少次为真。

int main(){
int ival = 9;
    while (ival){
        [&ival]()->bool{if (ival>0) return ival-- == 0; }();
        cout << ival << " ";
    }
return 0;}

参数绑定

bind定义在头文件 functional 中
auto newCallable = std::bind(callabel, arg_list);

placeholders
placeholders命名空间也也定义在头文静 functional 中

bool check_size(const string &s, string::size_type sz){
	return s.size() >= sz;
}
auto wc = std::find_if(words.begin(), words.end(), 
					    std::bind(check_size, std::placeholders::_1) );

using namesapce namespace_name;
using namespace std::placeholders;

auto g = std::bind(f, a, b, _2, c, _1);
//等价于
g(_1, _2) 映射为 f(a, b, _2, c, _1)
//如:
g(X, Y) 会调用 f(a, b, Y, c, X)
auto isShorter(const string&a, const string&b) -> bool{
	return a.size() < b.size();
}
bind(isShorter, _2, _1);

以引用的方式传递参数
ref 和 cref 标准库函数均定义在头文件 functional 中

std::for_each(words.begin(), words.end(), bind(print, std::ref(os), _1, ' ') );

迭代器

头文件 iterator

  • 插入迭代器 insert iterator
  • 流迭代器 stream iterator
  • 反向迭代器 reverse iterator
  • 移动迭代器 move iterator

插入迭代器

有点类似Python中的生成器,每次使用后,下次再使用输出改变
back_inserter : 调用 push_back()
front_inserter : 调用push_front
inserter : 调用insert

//若it是由inserter生成的迭代器
*it = val;
//equivalent
it = c.insert(it, val); //it指向新插入的元素
++ it ;                 //递增it使它指向原来的元素


list<int> lst1={1,2,3,4}, lst2, lst3;
//lst2 4,3,2,1
copy(lst.cbegin(), lst.cend(), front_inserter(lst2) );
//lst3 1,2,3,4
copy(lst.cbegin(), lst.cend(), inserter(lst3, lst3.begin() ) );

iostream迭代器

pass

反向迭代器

pass

泛型算法结构

泛型算法要求的迭代器操作可以分为5个迭代器类别
在这里插入图片描述
输入迭代器 input iterator:可以读取序列中的元素。它必须支持:

  • ==   !=
  • ++
  • 解引用(*), 解引用只会出现在赋值运算符的右侧
  • -> equivalent to (*it).member

**输出迭代器 output iterator ** :只写而不读元素。它必须支持:

  • ++
  • *, 只出现在赋值运算符的左侧

**前向迭代器 forward iterator ** :可读写元素。

**双向迭代器 forward iterator ** :可读写元素。

**随机访问迭代器 random-access iterator ** :可读写元素。支持:

  • < <= > >=
  • += + - -=
  • 迭代器之间的减法运算
  • 下标运算符(iter[n]), 与*(iter[n])等价

算法形参模式

**alg ( ** beg, end, other args );
**alg ( ** beg, end, dest, other args );
**alg ( ** beg, end, beg2, other args );
**alg ( ** beg, end, beg2, end2, other args );

算法命名规范

函数层重载

unique(beg, end);	     //使用 == 运算符比较元素
unique(beg, end, comp);  //使用谓词comp比较元素

_if 版本

find(beg, end, val);	  //找查输入范围中val第一次出现的位置
find_if(beg, end , pred); //找查令第一个pred(函数)为真的元素

replace(beg, end, odd_val, new_val);
replace_if(beg, end, pred, new_val);

区分拷贝元素的版本和不拷贝的版本 _copy

reverse(beg, end);			  //反转输入范围中元素的顺序
reverse_copy(beg, end, dest); //将元素按逆序拷贝到dest

//_copy + _if version
// remove odd from v1
remove_if(v1.begin(), v1.end(), [](int i){return i % 2;});
//copy even from v1 to v2 without changed v1
//首先从v1拷贝到v2,然后判断v2中的元素是否移除
remove_copy_if(v1.begin(), v1.end(), back_inserter(v2), 
				[](int i){return i % 2;});

replace_copy(beg, end, dest, old_val, new_val);
replace_copy_if(beg, end, dest, pred, new_val);

特定容器算法

对于list和forward_list,应该优先使用成员函数版本的算法,而不是通用算法
在这里插入图片描述
在这里插入图片描述
splice成员
在这里插入图片描述


总结

  标准库定义了大约100个类型无关的对序列进行操作的算法。
  五类迭代器:输入(读取)、输出(写入)、前向、双向及随机访问迭代器。

一元谓词,二元谓词

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值