算法库 分类 非修改式的算法:count,find,for_each
修改式的算法:copy,replace,remove,remove_if
排序操作;sort
二分查找:lower_bound,upper_bound
集合操作:set_intersection
堆相关的操作:make_heap,push_heap
取最值:max,min
数值操作:accmulate(累加)
未初始化的内存操作:uninialized_copy
for_each算法 一元函数:函数的参数是一个
二元函数:函数的参数是两个
一元谓词/断言:函数的参数是一个,并且函数的返回类型是bool
二元谓词/断言:函数的参数是两个,并且函数的返回类型是bool
1 2 3 4 5 6 void func (value) { cout << value << " " ; } vector<int > vec = {1 ,2 ,3 ,4 }; for_each(vec.begin (),vec.end (),func);
可以把函数实现放在括号里
1 2 3 for_each(vec.begin (),vec.end (),[](int &value)->void { cout << value <<" " ; });
lambda表达式—》匿名表达式由三部分组成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 []()->void {} int a = 10 ;[]()->void { cout << a << endl }; [a](int value)->void { cout << a << endl; }; [a](int value)->void { cout << a << endl; cout << value << endl; }(200 ); [a](int value)->void { value++; cout << a << endl; cout << value << endl; }(200 ); [a](int value)->void { a++; value++; cout << a << endl; cout << value << endl; }(200 ); [&a](int value)->void { a++; value++; cout << a << endl; cout << value << endl; }(200 ); cout << a << endl; [a](int value)mutable ->void { a++; value++; cout << a << endl; cout << value << endl; }(200 ); cout << a << endl;
lambda表达式调用
1 2 3 4 5 6 7 8 9 10 11 [a](int value)->void { cout << a << endl; cout << value << endl; }(200 ); auto f = [a](int value)->void { cout << a << endl; cout << value << endl; }; f (100 );
捕获列表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 void test () { int num = 10 ; int age = 60 ; string name ("wd" ) ; auto f =[num,&age](int value){ cout << value << endl; cout << num << endl; age += 10 ; cout << age << endl; }; f (22 ); auto f2 =[&num,&age,name](int value){ num += 10 ; age += 10 ; cout << value << endl; cout << num << endl; cout << age << endl; cout << name << endl; }; f2 (200 ); auto f3 =[&,name](int value){ num += 10 ; age += 10 ; cout << value << endl; cout << num << endl; cout << age << endl; cout << name << endl; }; f3 (200 ); auto f4 =[=&age](int value){ num += 10 ; age += 10 ; cout << value << endl; cout << num << endl; cout << age << endl; cout << name << endl; }; f4 (200 ); }
全局变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 int Gnum = 110 ;void test () { int num = 10 ; int age = 60 ; auto f3 =[&num,age](int value){ num += 10 ; age += 10 ; cout << value << endl; cout << num << endl; cout << age << endl; cout << name << endl; cout << Gnum << endl; }; }
捕获列表捕获的是局部变量, 对于全局变量无序捕获可以直接使用
类数据成员
1 2 3 4 5 6 7 8 class Ex { void test{ auto x = []{return _num}; auto x2 = [this ]{return _num}; auto x3 = [this ]{return _num++l}; } int _num; }
lambda的本质
1 2 3 4 5 6 7 8 class Example { void operator () (int value) const { } int # int age; };
lambda的返回值的接收 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include <functional> function<void (int )> f =[num,&age](int value){ cout << value << endl; cout << num << endl; age += 10 ; cout << age << endl; }; function<void (const string &,int )> f2 = [](const string &name,int value){ cout << "name=" << name << endl; cout << "value=" <<value << endl; }; f2 ("ads" ,100 );
remove_if 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <algorithm> bool void func (int value) { return value > 3 ; } void tese () { vector<int > vec = {1 ,2 ,3 ,4 ,5 }; for_each(vec.begin (),vec.end (),[](int &value){ cout << value <<" " ;}); auto it = remove_if (vec.begin (),vec.end (),func); vec.erase (it,vec.end ()); for_each(vec.begin (),vec.end (),[](int &value){ cout << value <<" " ;}); }
remove_if的通用性更强,这也是为什么底层遍历找到符合条件的元素直接删除,而是把不符合条件的元素往前移,然后返回的迭代器指向的就是所有不符合条件的元素的那部分的迭代器,配合erase就可以删除
并且也是可以用lambda表达式的
1 2 3 4 5 6 auto it = remove_if (vec.begin (),vec.end (),[](int value)->bool { return value > 5 ;});
bind1st和bind2nd bind1st可以绑定二元函数对象,将二元函数对象的第一个参数固定为x,bind2nd可以绑定二元函数对象,将二元函数对象的第二个参数固定为x
1 2 3 4 5 6 7 8 9 10 11 bind1st (less,3 );bool operator () (lhs = 5 , rhs) { return 3 < rhs; } bind2nd (greater,3 );bool operator () (lhs,rhs=5 ) { return rhs < 3 ; }
1 2 3 4 5 auto it = remove_if (vec.begin (),vec.end (),bind1st (less <int >(),3 ));auto it = remove_if (vec.begin (),vec.end (),bind2nd (greater <int >(),3 ));
==bind(重要)== 如何绑定参数的 1 2 3 4 5 6 7 8 int add (int x, int y) { return x + y; } void test () { auto f = bind (add,1 ,2 ); cout << "f()" << f () << endl; }
1 2 3 4 5 6 7 int mutiply (int x, int y, int z) { return x*y*z; } void test () { auto f2 = bind (mutiply,1 ,2 ,3 ); cout <<"f2()" << f2 ()<< endl; }
bind进行绑定的时候,绑定的是函数的地址
因为函数名就是函数地址,所以写函数名其实也是传的也是函数的入口地址,而且bind参数绑定的都是右值
引用折叠
1 2 3 4 5 6 7 8 9 & && = &; && && = &&; & & = &; && & = &; template <class F >void func (F && f) {}template <class F >void func (F & f) {}
bind绑定成员函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Example {public : int add (int x, int y) { return x+y; } }; int test () { auto f3 = bind (&Example::add,100 ,200 ); cout <<"f3()" << f3 ()<< endl; Example ex; auto f4 = bind (&Example::add,&ex,100 ,200 ); cout <<"f4()" << f4 ()<< endl; }
如果绑定静态成员函数呢
1 2 3 4 5 6 7 8 9 10 class Example {public : static int add (int x, int y) { return x+y; } } int test () { auto f4 = bind (&Example::add,100 ,200 ); cout <<"f4()" << f4 ()<< endl; }
bind可以绑定一部分参数,另一部分参数不绑定吗
1 2 auto f4 = bind (add,100 );cout << "f4(300)" << f4 (300 ) << endl;
1 2 3 using namespace std::placeholders;auto f4 = bind (add,100 ,_1);cout <<"f4(300)" << f4 (300 ) << endl;
==占位符==
1 2 3 using namespace std::placeholders;auto f4 = bind (add,100 ,_2);cout <<"f4(300)" << f4 (300 ,50 ,60 ) << endl;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 void func (int x1,int x2,int x3,const int &x4,int x5) { cout <<"x1 =" << x1 << endl <<"x2 = " << x2 << endl <<"x3 = " << x3 << endl <<"x4 = " << x4 << endl <<"x5 = " << x5 << endl } void test () { int number = 500 ; using namespace std::placeholders; bind (func,100 ,_3,_1,number,number); number = 3000 ; f (1 ,20 ,300 ,400 ,5000 ); }
引用的包装器
1 bind (func3,100 ,_3,_1,std::cref (number),number);
bind函数的返回值是什么类型?
1 2 3 4 5 6 7 8 auto f2 = bind (mutiply,1 ,2 ,3 );function<int ()> f2 = bind (mutiply,1 ,2 ,3 ); function<int (int )> f4 = bind (add,100 ,_1); function<int ()> f5 = bind (add,1 ,2 ); f2 = bind (add,1 ,2 );
因为function可以存放函数类型,将其称为函数的容器
bind绑定数据成员(了解) 1 2 3 4 5 6 7 8 9 10 11 12 class Example {public : static int add (int x, int y) { return x+y; } int data = 100 ; } void test () { Examble ex; function<int ()> f = bind (&Examble::data,&ex); cout << "f5()=" << f5 () << endl; }
由于形式与函数指针很类似 两者之间有什么区别?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 int func () { return 10 ; } int func2 () { return 20 ; } void test () { typedef int (*pFunc) () ; using pFunc = int (*)(); pFunc f1 = func (); cout << "f1()" << f1 () << endl; f2 = func2 (); cout << "f2()" << f2 () << endl; }
延迟调用函数的应用
虚函数,如果派生类中把虚函数重写了,再调用的时候才会调用派生类里的该函数,也就是把编译的时候能够确定的事件延迟到运行时才能确定–c++的多态
==如何用c语言实现多态?==
使用结构体配合函数指针
函数指针的局限性
1 2 3 4 5 6 7 8 int fun3 (int x) { return x; } void test () { typedef int (*pFunc) () ; pFunc f = func3; }
包括了函数指针的定义、函数指针的延迟调用思想、函数指针可以注册回调函数与执行回调函数,函数指针只能执行某些类型的函数,不能随便指向其他类型的函数
vector中的push_back导致迭代器失效 1 2 3 4 5 6 7 8 9 10 11 12 vector<int > vec={1 }; bool flag = true ;for (auto it =vec.begin (); it != vec.end (); ++it){ cout << *it << " " ; if (flag){ vec.push_back (20 ); falg = false ; } }
解决,重置迭代器
1 2 3 4 5 6 7 8 9 10 vector<int > vec={1 }; bool flag = true ;for (auto it =vec.begin (); it != vec.end (); ++it){ cout << *it << " " ; if (flag){ vec.push_back (20 ); falg = false ; it = vec.begin (); } }
或者,把就迭代器的vec.end()用一个变量保存一下,这样即使扩容,那么也不会出问题
晚上练习 第一题 Q:算法库中有哪些类型的操作?什么是函数对象?
A:算法库的分类:
非修改式的算法:count, find, for_each
修改式的算法:copy ,replace,remove,remove_if
排序操作:sort
二分查找:lower_bound, upper_bound
集合操作:set_intersection
堆相关的操作:make_heap,push_heap
取最值:max min
数值操作: accmulate
未初始化的内存操作:uninialized_copy
函数对象:
函数对象就是例如像类的实例,可以像函数一样被调用,具体是在该类中重载了()运算符,也就是有一个operator()()函数,然后使用函数对象的时候就可以像一个函数一样的调用它了
第二题 Q:容器、迭代器、算法之间的关系是怎样的?他们是如何结合在一起的?
A:我认为容器是基础,迭代器是工具,算法可以利用迭代器来对容器进行一些需要的操作,三者通过协同工作来提供强大的数据操作能力
三者的结合方式:
容器提供迭代器,每个容器都提供一种或多种迭代器,用于访问其元素.
算法使用迭代器:算法一般通过迭代器来操作数据,算法函数通常接收一 对迭代器作为参数,定义了操作的范围
迭代器提供统一的接口:迭代器提供了统一的接口,使得算法可以独立于容器进行设计和实现,这样算法可以应用于任何支持相应迭代器类型的容器
第三题 Q:什么是迭代器失效问题?该问题是如何产生的?怎样避免产生迭代器失效问题?
A:迭代器失效是指容器已经发生扩容或者其他情况,使得存储空间不再这片空间了,然后迭代器仍然指向的是旧空间,则该迭代器就已经失效了
一般情况的下是容器发生扩容,然后操作系统开辟了一片的新的空间,则原来这片空间就已经失效了,但是指向旧空间的迭代器并不知道该空间已经失效,然后就产生了迭代器失效的问题
每次使用迭代器之前就更新一下迭代器,例如 it = vec.begin();
第四题 Q:什么是回调函数,注册回调函数,执行回调函数?
A:回调函数是一个函数,它作为参数传递给另一个函数,在该函数执行过程中或者执行结束后被调用
注册回调函数是指将一个函数指针传递给另一个函数,以便在适当的时候调用它,这通常涉及保存函数指针,以便以后可以调用它
执行回调函数是指在适当的时候,通过调用保存的函数指针来执行回调函数的过程
第五题 Q:Leetcode 20题
https://leetcode-cn.com/problems/valid-parentheses/
给定一个只包括 ‘(‘,’)’,’{‘,’}’,’[‘,’]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 每个右括号都有一个对应的相同类型的左括号。
示例 1:
输入:s = “()” 输出:true 示例 2:
输入:s = “()[]{}” 输出:true 示例 3:
输入:s = “(]” 输出:false
提示:
1 <= s.length <= 104 s 仅由括号 ‘()[]{}’ 组成
A:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Solution {public : bool isValid (string s) { stack<char > st; for (int i = 0 ; i < s.size (); ++i){ if (s[i] == '(' || s[i] == '[' || s[i] == '{' ){ st.push (s[i]); } else { if (st.empty ()) return false ; char ch = st.top (); st.pop (); if (ch == '(' && s[i] != ')' ) return false ; else if (ch == '[' && s[i] != ']' ) return false ; else if (ch == '{' && s[i] != '}' ) return false ; } } if (!st.empty ()) return false ; return true ; } };