CJC From NJU wrote a C++ STL Tutorial . This is a perfect learning material for STL beginners to get familiar with C++ STL. Hope this note can help you learn the material!
概述
STL包含什么?
STL是一个基于模版实现的标准模板库,包含容器类模版、算法模版和迭代器模版。
其中迭代器是指向容器的元素,是容器和算法之间的桥梁。
容器(Container)
vector<元素类型>
快速访问任意位置的元素,主要在元素序列的尾部增加/删除元素
用动态数组实现
list<元素类型>
在元素序列中任意位置上插入/删除元素
用双向链表实现
C++11中增加了forward_list
容器,本质上是一个单向链表 ,定义在头文件forward_list
中。
deque<元素类型>
在元素序列的两端增加/删除元素,快速访问任意位置的元素
用分段的连续空间结构 实现
stack<元素类型>
仅在元素序列的尾部增加/删除元素
可基于deque
、list
或vector
来实现
queue<元素类型>
仅在元素序列的尾部增加、头部删除元素
可基于deque
和list
来实现。
priority_queue<元素类型>
每次增加/删除元素之后,对元素位置进行调整,使得头部元素总是最大的。也就是说,每次删除操作总是从头部把最大(优先级最高)的元素去掉。
可基于deque
和vector
来实现
map<key,value> 和 multimap<key,value>
根据key来访问元素,容器中每个元素是一个pair<key, value>
结构
对于map
,不同元素的关键字不能相同;对于multimap
,不同元素的关键字可以相同。
常用某种二叉树 来实现
有时候我们不需要排序,所以C++11中新增加了unordered_map
和unordered_multimap
容器。
set<元素类型> 和 multiset<元素类型>
它们分别是map
和multimap
的特例,每个元素只有key而没有value
C++11中增加了unordered_set
和unordered_multiset
容器。
basic_string<字符类型>
与vector
类似,不同之处在于其元素为字符类型
string
和wstring
分别是它的两个实例:
basic_string<char>
basic_string<wchar_t>
迭代器(Iterator)
迭代器的分类(五种基本迭代器)
根据访问修改权限分类:
输出迭代器(output iterator,记为:OutIt ):修改它所指向的容器元素
输入迭代器(input iterator,记为:InIt ):读取它所指向的容器元素
根据迭代方式分类:
前向迭代器(forward iterator,记为:FwdIt )
双向迭代器(bidirectional iterator,记为:BidIt )
随机访问迭代器(random-access iterator,记为:RanIt )
对于vector
、deque
以及basic_string
容器类,与它们关联的迭代器类型为随机访问迭代器(RanIt)
对于list
、map/multimap
以及set/multiset
容器类,与它们关联的迭代器类型为双向迭代器(BidIt)
queue
、stack
和priority_queue
容器类,不支持迭代器!
在需要箭头左边迭代器的地方可以用箭头右边的迭代器去替代。
反向迭代器(reverse iterator)
用于对容器元素从尾到头进行反向遍历,可以通过容器类的成员函数rbegin
和rend
可以获得容器的尾和首元素的反向迭代器 。
插入迭代器(insert iterator)
back_insert_iterator
(用于在尾部插入元素)
front_insert_iterator
(用于在首部插入元素)
insert_iterator
(用于在任意指定位置插入元素)
可以分别通过函数back_inserter
、front_inserter
和inserter
来获得,函数的参数为容器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 std::vector<int > vec; std::list<int > lst; std::vector<int > middle_vec{10 , 20 , 30 , 40 , 50 }; std::copy (source.begin (), source.end (), std::back_inserter (vec)); std::copy (source.begin (), source.end (), std::front_inserter (lst));auto insert_pos = middle_vec.begin () + 2 ; std::copy (source.begin (), source.end (), std::inserter (middle_vec, insert_pos));
使用迭代器求解约瑟夫问题
N 个人围成一圈,从第 1 个人开始报数,每报到第 M 个人就让他出列并从下一个人重新开始报数,直到所有人都出列为止。问最后一个出列的人是原来的第几号。
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 int m,n; cout << "请输入小孩的个数和要报的数:" ; cin >> n >> m; list<int > children; for (int i=0 ; i<n; i++) children.push_back (i); list<int >::iterator current; current = children.begin (); while (children.size () > 1 ) { for (int count = 1 ; count < m; count++) { current++; if (current == children.end ()) current = children.begin (); } current = children.erase (current); if (current == children.end ()) current = children.begin (); } cout << "The winner is No." << *current << "\n" ;
算法(Algorithm)
在STL中,我们把某些迭代器传递给算法,算法通过迭代器来访问和遍历相应容器中的元素。
用算法对容器中的元素进行操作时,大都需要用两个迭代器来指出要操作的元素的范围 。
例如:
1 void sort (RanIt first, RanIt last) ;
有些算法可以有多个操作范围,这时,除第一个范围外,其它范围可以不指定最后一个元素位置,它由第一个范围中元素的个数决定。例如:
1 OutIt copy (InIt src_first, InIt src_last, OutIt dst_first) ;
算法的自定义操作
自定义操作可分为:
例如:
1 2 3 4 5 6 7 Fun for_each (InIt first, InIt last, Fun f) ;void f (int x) { cout << ' ' << x; } vector<int > v; ...... for_each(v.begin (), v.end (), f);
例如,对于下面的元素“变换/映射 ”算法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 OutIt transform (InIt src_first, InIt src_last, OutIt dst_first, Op f) ;OutIt transform (InIt1 src_first1, InIt1 src_last1, InIt2 src_first2, OutIt dst_first, BinOp f) ;int f1 (int x) { return x * x; }int f2 (int x1, int x2) { return x1 + x2; } vector<int > v1,v2,v3,v4; ...... transform (v1.begin (),v1.end (),v3.begin (),f1); transform (v1.begin (),v1.end (),v2.begin (),v4.begin (),f2);
仿函数(Functor)
这里稍微拓展一下**仿函数(Functor)**的使用,在后续会有详细的介绍。
利用仿函数实现算法的自定义操作:
定义函数对象类如下:
1 2 3 4 5 6 7 class MatchMajor { Major major;public : MatchMajor (Major m) { major = m; } bool operator () (Student& st) { return st.get_major () == major; } };
统计某某专业的人数:
1 2 3 4 5 count_if (students.begin (), students.end (), MatchMajor (COMPUTER));count_if (students.begin (), students.end (), MatchMajor (PHYSICS));count_if (students.begin (), students.end (), MatchMajor (XXX));
匿名函数(lambda表达式)
https://www.runoob.com/cplusplus/cpp-functions.html
Lambda 表达式具体形式如下:
1 [capture](parameters)->return -type{body}
例如:
1 [](int x, int y){ return x < y ; }
如果没有返回值可以表示为:
1 [capture](parameters){body}
例如:
在一个更为复杂的例子中,返回类型可以被明确的指定如下:
1 [](int x, int y) -> int { int z = x + y; return z + x; }
在Lambda表达式内可以访问当前作用域的变量,这是Lambda表达式的闭包(Closure)行为。与JavaScript闭包不同,C++变量传递有传值和传引用的区别。可以通过前面的[]来指定:
1 2 3 4 5 6 [] [x, &y] [&] [=] [&, x] [=, &z]
需要注意的是,[]是空捕获列表的lambda表达式是不能访问外部非静态的局部变量 的,但是可以访问全局变量和静态的局部变量,因为他们的生命周期覆盖整个程序运行期间
利用lambda表达式实现算法的自定义操作:
1 2 3 4 5 6 7 8 9 10 cout << "计算机专业女生的人数是:" << count_if (students.begin (),students.end (), [](Student &st) { return (st.get_major () == COMPUTER) && (st.get_sex () == FEMALE); });sort (students.begin (),students.end (), [](Student &st1,Student &st2) { return st1.get_no ()<st2.get_no ();});
最后
这里附上微软的C++文档pdf链接:
https://box.nju.edu.cn/f/c19cd234d4a94fd2b458/
后续将会介绍各种常用STL的用法。熟悉这些常见的STL用法+查文档是C++开发的基本要求。
容器(Container)
选择容器
容器分为序列容器和容器适配器。
选择序列容器:
选择容器适配器:
字符串(string)
string本质上是一个动态char数组
常用API
1 2 3 4 5 6 7 8 string ();string (const string& str);string (const char * s);string (int n, char c);
=
赋值操作符:
1 2 3 4 5 6 string& operator =(const char * s); string& operator =(const string& s); string& operator =(const char c);
assign
成员函数:
1 2 3 4 5 6 7 8 9 10 string& assign (const char * s) ; string& assign (const char * s, int n) ; string& assign (const string& s) ; string& assign (int n, char c) ; string& assign (const string& s, int start, int n) ;
下标获取操作符:
1 2 char & operator [](int n);
使用下标操作符获取字符时,如果下标越界,程序将会强制终止。
at
成员函数:
使用at方法获取字符时,如果下标越界,at方法内部会抛出异常(exception
),可以使用try-catch
捕获并处理该异常。示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 string s = "hello world" ;try { s.at (100 ); }catch (out_of_range& e) { cout << e.what () << endl; }
+=
复合操作符号:
1 2 3 4 5 6 7 string& operator +=(const string& str); string& operator +=(const char * str); string& operator +=(const char c);
append
成员函数:
1 2 3 4 5 6 7 8 9 10 string& append (const char * s) ; string& append (const char * s, int n) ; string& append (const string &s) ; string& append (const string&s, int pos, int n) ; string& append (int n, char c) ;
find
成员函数:
1 2 3 4 5 6 7 8 int find (const string& str, int pos = 0 ) const ; int find (const char * s, int n = 0 ) const ; int find (const char * s, int pos, int n) const ; int find (const char c, int pos = 0 ) const ;
当查找失败时,find
方法会返回-1
,-1
已经被封装为string的静态成员常量string::npos
1 static const size_t nops = -1 ;
rfind
成员函数:
1 2 3 4 5 6 7 8 int rfind (const string& str, int pos = npos) const ; int rfind (const char * s, int pos = npos) const ; int rfind (const char * s, int pos, int n) const ; int rfind (const char c, int pos = npos) const ;
find
方法通常查找字串第一次出现的位置,而rfind
方法通常查找字串最后一次出现的位置。
rfind(str, pos)
的实际的开始位置是pos + str.size()
,即从该位置开始(不包括该位置字符)向前寻找匹配项,如果有则返回字符串位置,如果没有返回string::npos
。
-1
其实是size_t
类的最大值,所以string::npos
还可以表示“直到字符串结束”,rfind中pos的默认参数是字符串最后一个字符的后面一个位置。
replace
成员函数:
1 2 3 4 string& replace (int pos, int n, const string& str) ; string& replace (int pos, int n, const char * s) ;
compare
成员函数:
1 2 int compare (const string& s) const ; int compare (const char * s) const ;
compare
函数依据字典序比较,在当前字符串比给定字符串小时返回-1
,在当前字符串比给定字符串大时返回1
,相等时返回0
。
比较操作符:
1 2 3 4 5 6 7 8 9 10 11 12 bool operator <(const string& str) const ;bool operator <(const char * str) const ;bool operator <=(const string& str) const ;bool operator <=(const char * str) const ;bool operator ==(const string& str) const ;bool operator ==(const char * str) const ;bool operator >(const string& str) const ;bool operator >(const char * str) const ;bool operator >=(const string& str) const ;bool operator >=(const char * str) const ;bool operator !=(const string& str) const ;bool operator !=(const char * str) const ;
string
类重载了所有的比较操作符,其含义与比较操作符本身的含义相同。
substr
成员函数:
1 2 string substr (int pos = 0 , int n = npos) const ;
insert
成员函数:
1 2 3 string& insert (int pos, const char * s) ; string& insert (int pos, const string& str) ; string& insert (int pos, int n, char c) ;
返回值是插入后的字符串结果,erase
同理。其实就是指向自身的一个引用。
erase
成员:
1 string& erase (int pos, int n = npos) ;
默认一直删除到末尾。
string
转const char
:
1 2 string str = "demo" ;const char * cstr = str.c_str ();
const char
转string
:
1 2 const char * cstr = "demo" ;string str (cstr) ;
C++可以隐式地将const char *
转换为string,但反过来不行。
string相关的全局函数
1 2 3 4 5 6 7 8 9 10 int tolower (int c) ; int toupper (int c) ; string str = "Hello, World!" ;transform (str.begin (), str.end (), str.begin (), toupper); transform (str.begin (), str.end (), str.begin (), tolower);
int
/double
转string
c++11标准新增了全局函数std::to_string
,十分强大,可以将很多类型变成string
类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 string to_string (int val) ;string to_string (long val) ;string to_string (long long val) ;string to_string (unsigned val) ;string to_string (unsigned long val) ;string to_string (unsigned long long val) ;string to_string (float val) ;string to_string (double val) ;string to_string (long double val) ;
string
转int
/double
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 int stoi (const string& str, size_t * idx = 0 , int base = 10 ) ;long stol (const string& str, size_t * idx = 0 , int base = 10 ) ;long long stoll (const string& str, size_t * idx = 0 , int base = 10 ) ;unsigned long stoul (const string& str, size_t * idx = 0 , int base = 10 ) ;unsigned long long stoull (const string& str, size_t * idx = 0 , int base = 10 ) ;float stof (const string& str, size_t * idx = 0 ) ;double stod (const string& str, size_t * idx = 0 ) ;long double stold (const string& str, size_t * idx = 0 ) ;
与之类似的在同一个库里的还有一组基于字符数组(C风格字符串)的函数如下。
1 2 3 4 5 6 7 int atoi (const char * str) ; long atol (const char * str) ; long long atoll (const char * str) ; double atof (const char * str) ;
向量(vector)
array
是静态空间,而vector
是动态空间
vector提供的是随机访问迭代器(Random Access Iterator ),其内部用普通指针实现。
vector数据结构
就是简单的线性连续空间,两个迭代器_Myfirst
和_Mylast
分别指向配置得来的连续空间中已被使用的范围,迭代器Myend
指向整块连续内存空间的尾端
常用API
1 2 3 4 vector<T> v; vector<T> v (T* v1.begin(), T* v1.end()) ; vector<T> v (int n, T elem) ; vector<T> v (const vector<T> v1) ;
1 2 3 assign (beg, end); assign (n, elem); vector& operator =(const vector& vec);
互换操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 int size () ; bool empty () ; void resize (int num) ; void resize (int num, T elem) ; int capacity () ; void reserve (int len) ;
1 2 3 4 5 T& at (int idx) ; T& operator [](int idx); T& front () ; T& back () ;
vector是单向开口的,只有在尾部插入和删除元素效率较高,向其它位置插入和删除元素需要大量移位操作,效率很低。
1 2 3 4 5 6 7 8 9 10 insert (const_iterator pos, T elem); insert (const_iterator pos, int n, T elem); insert (pos, beg, end); push_back (T elem); pop_back (); erase (const_iterator start, const_iterator end); erase (const_iterator pos); clear ();
双向队列(deque)
vector是单向开口的连续内存空间,而deque是双向开口的连续线性空间:
deque在头部尾部插入删除元素都都是使用常数项时间
deque是动态的分段连续空间组合而成,随时可以增加新空间链接起来
deque虽然也支持随机访问,但实现较复杂,需要随机访问最好用vector。
常用API
1 2 3 4 deque<T> deqT; deque (beg, end); deque (int n, T elem); deque (const deque& deq);
1 2 3 4 5 6 assign (beg, end); assign (int n, T elem); deque& operator =(const deque& deq); swap (deq);
1 2 3 4 5 6 7 8 9 int size () ; bool empty () ; void resize (int num) ; void resize (int num, T elem) ;
1 2 3 4 5 push_back (T elem); push_front (T elem); pop_back (); pop_front ();
1 2 3 4 5 T& at (int idx) ; T& operator [](int idx); T& front () ; T& back () ;
1 2 3 4 5 6 const_iterator insert (const_iterator pos, T elem) ; void insert (const_iterator pos, int n, T elem) ; void insert (pos, beg, end) ;
1 2 3 4 5 clear (); iterator erase (iterator beg, iterator end) ;iterator erase (iterator pos) ;
栈(stack)
不允许遍历行为,不提供迭代器!
常用API
1 2 stack<T> stkT; stack (const stack& stk);
1 stack& operator =(const stack& stk);
1 2 3 void push (T elem) ; void pop () ; T& top () ;
1 2 bool empty () ; int size () ;
队列(queue)
先进先出,从队头pop,从队尾push
外界只会访问queue的顶端元素,queue不提供遍历功能,因此没有迭代器
queue中的元素在内存中不一定连续
常用API
1 2 queue<T> queT; queue (const queue& que);
1 2 3 4 void push (T elem) ; void pop () ; T& back () ; T& front () ;
1 queue& operator =(const queue& que);
1 2 bool empty () ; int size () ;
链表(list)
list容器是一个循环的双向链表 。
链表对于任意位置插入或删除都是常数项时间。
常用API
1 2 3 4 list<T> lstT; list (beg, end); list (int n, T elem); list (const list& lst);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 void push_back (T elem) ; void pop_back () ; void push_front (T elem) ; void pop_front () ; insert (iterator pos, elem); insert (iterator pos, n, elem); insert (iterator pos, beg, end); void clear () ; erase (beg, end); erase (pos); remove (elem);
1 2 3 4 5 6 7 8 9 int size () ; bool empty () ; void resize (int num) ;void resize (int num, T elem) ;
1 2 3 4 5 6 assign (beg, end); assign (n, elem); list& operator =(const list& lst); swap (lst);
1 2 3 4 5 6 7 8 void reverse () ; void sort () ; void sort (bool (*cmp)(T item1, T item2)) ;
集合(set/multiset)
set和multiset的底层实现是红黑树
不可以通过set的迭代器改变set元素的值,因为其元素值就是key值,随意改变会破坏set组织,因此set的iterator是const_iterator
。
常用API
1 2 3 set<T> st; multiset<T> mst; set (const set& st);
1 2 3 set& operator =(const set& st); swap (st);
1 2 int size () ; bool empty () ;
1 2 3 4 5 6 7 pair<iterator, bool > insert (T elem) ; clear (); iterator erase (pos) ; iterator erase (beg, end) ; erase (T elem);
插入之前可以指定排序规则:
1 2 3 4 5 6 7 8 9 10 11 12 13 class MyCompare {public : bool operator () (int v1, int v2) { return v1 > v2; } }; set<int , MyCompare> s;
自定义的数据类型需要指出排序规则。
当然,也可以通过重载小于操作符的方式指出。
1 2 3 4 5 6 7 8 9 10 iterator find (T key) ; int count (T key) ;iterator lower_bound (T keyElem) ;iterator upper_bound (T keyElem) ;pair<iterator, iterator> equal_range (T keyElem) ;
上述几个方法若不存在,返回值都是尾迭代器。
对组的构造和使用:
1 2 3 4 5 6 pair<T1, T2> p (k, v) ; pair<T1, T2> p = make_pair (k, v); cout << p.first << p.second << endl;
映射(map/multimap)
map和multimap的底层实现是红黑树
常用API
1 2 map<T1, T2> mapTT; map (const map& mp);
1 2 map& operator =(const map& mp); swap (mp);
1 2 int size () ; bool empty () ;
1 2 3 4 5 6 7 8 9 pair<iterator, bool > insert (pair<T1, T2> p) ; T2& operator [](T1 key);
1 2 3 4 5 6 7 map<string, int > myMap; myMap.insert (pair <string, int >("apple" , 5 )); myMap.insert (make_pair ("banana" , 3 )); myMap.insert (map<string, int >::value_type ("orange" , 4 ));
map指定排序规则的方式和set类似,都是利用functor在模版类型表的最后一个参数处指定。
1 2 3 4 void clear () ; iterator erase (iterator pos) ; iterator erase (beg, end) ; erase (keyElem);
1 2 3 4 5 6 7 8 9 10 11 iterator find (T1 key) ; int count (T1 keyElem) ;iterator lower_bound (T keyElem) ;iterator upper_bound (T keyElem) ;pair<iterator, iterator> equal_range (T keyElem) ;
优先级队列(priority_queue)
优先级队列的底层实现是最小/最大二叉堆
常用API
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <queue> priority_queue<int > maxHeap; priority_queue<int , vector<int >, greater<int >> minHeap;void push (const value_type& val) ; void pop () ; value_type top () const ; bool empty () const ; size_type size () const ;
自定义优先级
自定义比较函数对象(仿函数)
1 2 3 4 5 6 7 8 9 10 struct CustomCompare { bool operator () (const int & a, const int & b) { return a % 10 > b % 10 ; } }; priority_queue<int , vector<int >, CustomCompare> customPQ;
对于自定义类型,重载比较运算符
注意构建最大堆需要重载的是小于运算符,较小的放较大的下面,堆顶是最大的元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 struct Task { int id; int priority; bool operator <(const Task& other) const { return priority < other.priority; } }; priority_queue<Task> taskQueue;struct ReverseCompare { bool operator () (const Task& a, const Task& b) { return a.priority > b.priority; } }; priority_queue<Task, vector<Task>, ReverseCompare> minTaskQueue;
无序容器(unordered_*
)
无序容器包括:unordered_map
、unordered_multimap
、unordered_set
、unordered_multiset
无序容器 vs 有序容器
无序容器的底层实现是哈希表,有序容器的实现是红黑树
哈希表的插入/查找/删除的平均时间复杂度都是O(1),但最坏时间复杂度是O(n)(哈希冲突严重时)
红黑树插入/查找/删除的平均和最坏时间复杂度都是O(log n)
无序容器通常消耗更多的内存,但在平均情况下查找/插入/删除更快速
有序容器用在需要对元素排序时,能保证稳定的最坏情况性能,相对节省内存空间
函数对象/仿函数(Functor)
适配器
函数对象适配器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class myPrint : public binary_function<int , int , void > {public : void operator () (int val, int base) const { cout << val + base << endl; } }int main () { vector<int > v; for (int i = 0 ; i < 10 ; i++) v.push_back (i); int n; cin >> n; for_each(v.begin (), v.end (), bind2nd (myPrint (), n)); return 0 ; };
取反适配器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class GreaterThanFive : public unary_function<int , bool > {public : bool operator () (int val) const { return val > 5 ; } }int main () { vector<int > v; for (int i = 0 ; i < 10 ; i++) v.push_back (i); vector<int >::iterator pos = find_if (v.begin (), v.end (), not1 (GreaterThanFive ())); if (pos != v.end ()) cout << *pos << endl; return 0 ; }
或者用更简便的方法:
1 vector<int >::iterator pos = find_if (v.begin (), v.end (), not1 (bind2nd (greater <int >(), 5 )));
函数指针适配器
1 2 for_each(v.begin (), v.end (), bind2nd (ptr_fun (myPrint), n));
成员函数适配器
1 2 3 for_each(v.begin (), v.end (), mem_fun_ref (&Dog::bark));
偏函数
对于一个多参数的函数,在某些应用场景下,它的一些参数往往取固定值,可以针对这样的函数,生成一个新函数,该新函数不包含原函数中已指定固定值的参数。
例如,对于下面的print函数:
1 void print (int n, int base) ;
由于它常常用来按十进制输出,因此,可以基于print生成一个新函数print10,只接受一个参数n,base固定为10:
1 2 3 4 5 6 #include <functional> using namespace std;using namespace std::placeholders; function<void (int )> print10 = bind (print, _1, 10 );print10 (23 );
算法(Algorithm)
自定义的类如果想直接使用算法库,则需补全默认构造函数、拷贝构造函数、析构函数、赋值操作符、小于操作符、等于操作符。
遍历算法
for_each
1 2 3 4 5 6 7 8 for_each(iterator beg, iterator end, _callback);
1 2 3 4 5 6 7 8 9 10 iterator transform (iterator beg1, iterator end1, iterator beg2, _callback) ;
查找算法
find
1 2 3 4 5 6 7 8 iterator find (iterator beg, iterator end, value) ;
find_if
1 2 3 4 5 6 7 8 iterator find_if (iterator beg, iterator end, _callback) ;
利用find_if实现自定义类的find操作的时候,之前的函数适配器可能会派上用场。
adjacent_find
1 2 3 4 5 6 7 8 iterator adjacent_find (iterator beg, iterator end, _callback) ;
binary_search
1 2 3 4 5 6 7 8 9 bool binary_search (iterator beg, iterator end, value) ;
count
1 2 3 4 5 6 7 8 int count (iterator beg, iterator end, value) ;
count_if
1 2 3 4 5 6 7 8 int count_if (iterator beg, iterator end, _callback) ;
排序算法
merge
1 2 3 4 5 6 7 8 9 10 merge (iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
sort
1 2 3 4 5 6 7 sort (iterator beg, iterator end, _callback);
random_shuffle
1 2 3 4 5 6 random_shuffle (iterator beg, iterator end);
如果想要每次打乱不同,需要自己设置随机数种子:
1 2 3 4 5 6 7 8 #include <ctime> using namespace std;int main () { srand ((unsigned int )time (NULL )); ...... }
reverse
1 2 3 4 5 6 reverse (iterator beg, iterator end);
拷贝和替换算法
copy
1 2 3 4 5 6 7 copy (iterator beg, iterator end, iterator dest);
使用copy算法快速打印容器:
1 2 3 4 5 vector<int > v = {1 , 2 , 3 , 4 , 5 }; for_each(v.begin (), v.end (), [](int val){cout << val << " " ;});copy (v.begin (), v.end (), ostream_iterator <int >(cout, " " ));
replace
1 2 3 4 5 6 7 8 replace (inerator beg, iterator end, oldvalue, newvalue);
replace_if
1 2 3 4 5 6 7 8 replace_if (inerator beg, inerator end, _callback, newvalue);
swap
1 2 3 4 5 6 swap (container c1, container c2);
算数生成算法
accumulate
1 2 3 4 5 6 7 8 #include <numeric> accumulate (iterator beg, iterator end, value);
fill
1 2 3 4 5 6 7 fill (iterator beg, iterator end, value);
集合算法
set_intersection
1 2 3 4 5 6 7 8 9 10 11 set_intersection (iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
set_union
1 2 3 4 5 6 7 8 9 10 11 set_union (iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
set_difference
1 2 3 4 5 6 7 8 9 10 11 set_difference (iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);