C++学习一STL

文章目录

  • 一、STL基本概念
    • 1.泛型程序设计
    • 2.STL中的基本的概念
  • 二、容器概述
    • 1.简介
    • 2.顺序容器
    • 3.关联容器
    • 4.容器适配器
    • 5.成员函数
  • 三、迭代器
    • 1.概念
    • 2.双向迭代器
    • 3.随机访问迭代器
    • 4.容器上的迭代器类别
  • 四、算法
    • 1.概念
    • 2.不变序列算法
    • 2.变值算法
    • 4.删除算法
    • 5.变序算法
    • 6.排序算法
    • 7. 堆排序
    • 8.有序区间算法
    • 9.bitset
  • 五、STL中的“大”、“小”和“相等”
    • 1.STL中“大”“小” 的概念
    • 2.STL中“相等”的概念
  • 六、使用方法
    • 1.vector
    • 2.deque
    • 3.双向链表list
    • 4.set和multiset
    • 5.map和multimap
    • 6.stack
    • 7.queue
    • 7.priority_queue
    • 8.容器适配器的元素个数
  • 七、函数对象
    • 1.定义
    • 2.函数对象的应用
    • 3.greater 函数对象类模板
    • 4.引入函数对象后,STL中的“大”,“小”关系
  • 总结


一、STL基本概念

1.泛型程序设计

  1. 简单地说就是使用模板的程序设计法。
  2. 将一些常用的数据结构(比如链表,数组,二叉树)和算法(比如排序,查找)写成模板,以后则不论数据结构里放的是什么对象,算法针对什么样的对象,则都不必重新实现数据结构,重新编写算法。
  3. 标准模板库 (Standard Template Library) 就是一些常用数据结构和算法的模板的集合。
  4. 有了STL,不必再写大多的标准数据结构和算法,并且可获得非常高的性能。

2.STL中的基本的概念

  1. 容器:可容纳各种数据类型的通用数据结构,是类模板

  2. 迭代器:可用于依次存取容器中元素,类似于指针

  3. 算法:用来操作容器中的元素的函数模板

      sort()来对一个vector中的数据进行排序find()来搜索一个list中的对象算法本身与他们操作的数据的类型无关,因此他们可以在从简单数组到高度复杂容器的任何数据结构上使用。
    

二、容器概述

1.简介

  1. 可以用于存放各种类型的数据(基本类型的变量,对象等)的数据结构,都是类模版,分为三种:

     1)顺序容器vector, deque,list2)关联容器set, multiset, map, multimap3)容器适配器stack, queue, priority_queue
    
  2. 对象被插入容器中时,被插入的是对象的一个复制品。许多算法,比如排序,查找,要求对容器中的元素进行比较,有的容器本身就是排序的,所以,放入容器的对象所属的类,往往还应该重载 == 和 < 运算符。

2.顺序容器

容器并非排序的,元素的插入位置同元素的值无关。
有vector,deque,list 三种

  1. vector 头文件 <vector>
    动态数组。元素在内存连续存放。随机存取任何元素都能在常数时间完成。在尾端增删元素具有较佳的性能(大部分情况下是常数时间)。
    在这里插入图片描述

  2. deque 头文件 <deque>
    双向队列。元素在内存连续存放。随机存取任何元素都能在常数时间完成(但次于vector)。在两端增删元素具有较佳的性能(大部分情况下是常数时间)。
    在这里插入图片描述
    在这里插入图片描述

  3. list 头文件 <list>
    双向链表。元素在内存不连续存放。在任何位置增删元素都能在常数时间完成。不支持随机存取。
    在这里插入图片描述

3.关联容器

  1. 元素是排序的
  2. 插入任何元素,都按相应的排序规则来确定其位置
  3. 在查找时具有非常好的性能
  4. 通常以平衡二叉树方式实现,插入和检索的时间都是 O(log(N))
  5. set/multiset 头文件 <set>
    set 即集合。set中不允许相同元素,multiset中允许存在相同的元素。
  6. map/multimap 头文件 <map>
    map与set的不同在于map中存放的元素有且仅有两个成员变量,一个名为first,另一个名为second, map根据first值对元素进行从小到大排序,并可快速地根据first来检索元素。
    map同multimap的不同在于是否允许相同first值的元素。
  7. stack :头文件 <stack>
    栈。是项的有限序列,并满足序列中被删除、检索和修改的项只能是最近插入序列的项(栈顶的项)。后进先出。
    在这里插入图片描述

4.容器适配器

  1. queue 头文件 <queue>
    队列。插入只可以在尾部进行,删除、检索和修改只允许从头部进行。先进先出。
    在这里插入图片描述
  2. priority_queue 头文件 <queue>
    优先级队列。最高优先级元素总是第一个出列

5.成员函数

  1. 顺序容器和关联容器中都有的成员函数

     begin 返回指向容器中第一个元素的迭代器end 返回指向容器中最后一个元素后面的位置的迭代器rbegin 返回指向容器中最后一个元素的迭代器rend 返回指向容器中第一个元素前面的位置的迭代器erase 从容器中删除一个或几个元素clear 从容器中删除所有元素
    
  2. 顺序容器的常用成员函数

     front :返回容器中第一个元素的引用back : 返回容器中最后一个元素的引用push_back : 在容器末尾增加新元素pop_back : 删除容器末尾的元素erase :删除迭代器指向的元素(可能会使该迭代器失效),或删除一个区间,返回被删除元素后面的那个元素的迭代器
    

三、迭代器

1.概念

  1. 用于指向顺序容器和关联容器中的元素
  2. 迭代器用法和指针类似
  3. 有const 和非 const两种
  4. 通过迭代器可以读取它指向的元素
  5. 通过非const迭代器还能修改其指向的元素
  6. 定义一个容器类的迭代器的方法可以是:
    容器类名::iterator 变量名;
    或者
    容器类名::const_iterator 变量名;
    访问一个迭代器指向的元素:
    * 迭代器变量名
  7. 迭代器上可以执行 ++ 操作, 以使其指向容器中的下一个元素。如果迭代器到达了容器中的最后一个元素的后面,此时再使用它,就会出错,类似于使用NULL或未初始化的指针一样。
#include <vector>
#include "iostream"using namespace std;int main(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(15);v.push_back(3);//常量迭代器vector<int>::const_iterator i;  for (i = v.begin();i != v.end();++i ) {cout << *i << "  " ;}cout << endl;//反向迭代器vector<int>::reverse_iterator ri;for (ri = v.rbegin();ri != v.rend();++ri ) {cout << *ri << "  " ;}cout << endl;//非常量迭代器vector<int>::iterator j;for( j = v.begin();j != v.end();j ++ )*j = 100;for( i = v.begin();i != v.end();i++ )cout << * i << ",";cout << endl;return 0;
}

2.双向迭代器

若p和p1都是双向迭代器,则可对p、p1可进行以下操作:

	++p, p++ 使p指向容器中下一个元素--p, p-- 使p指向容器中上一个元素* p 取p指向的元素p = p1 赋值p == p1 , p!= p1 判断是否相等、不等

3.随机访问迭代器

若p和p1都是随机访问迭代器,则可对p、p1可进行以下操作:

	双向迭代器的所有操作p += i 将p向后移动i个元素p -= i 将p向向前移动i个元素p + i 值为: 指向 p 后面的第i个元素的迭代器p - i 值为: 指向 p 前面的第i个元素的迭代器p[i] 值为: p后面的第i个元素的引用p < p1, p <= p1, p > p1, p>= p1p – p1 : p1和p之间的元素个数

4.容器上的迭代器类别

容器容器上的迭代器类别
vector随机访问
deque随机访问
list双向
set/multiset双向
map/multimap双向
stack不支持迭代器
queue不支持迭代器
priority_queue不支持迭代器

四、算法

1.概念

  1. 算法就是一个个函数模板, 大多数在 <algorithm> 中定义

  2. STL中提供能在各种容器中通用的算法,比如查找,排序等

  3. 算法通过迭代器来操纵容器中的元素。许多算法可以对容器中的一个局部区间进行操作,因此需要两个参数,一个是起始元素的迭代器,一个是终止元素的后面一个元素的迭代器。比如,排序和查找

  4. 有的算法返回一个迭代器。比如 find() 算法,在容器中查找一个元素,并返回一个指向该元素的迭代器

  5. 算法可以处理容器,也可以处理普通数组

  6. STL中的算法大致可以分为以下七类:
    1)不变序列算法
    2)变值算法
    3)删除算法
    4)变序算法
    5)排序算法
    6)有序区间算法
    7)数值算法

  7. 大多重载的算法都是有两个版本的,其中一个是用“==”判断元素是否相等,或用“<”来比较大小;而另一个版本多出来一个类型参数“Pred”,以及函数形参“Pred op”,该版本通过表达式“op(x,y)”的返回值是ture还是false,来判断x是否“等于”y,或者x是否“小于”y。如下面的有两个版本的min_element:

     iterate min_element(iterate first,iterate last);iterate min_element(iterate first,iterate last, Pred op);
    

2.不变序列算法

此类算法不会修改算法所作用的容器或对象,适用于所有容器。它们的时间复杂度都是O(n)的。

min求两个对象中较小的(可自定义比较器)
max求两个对象中较大的(可自定义比较器)
min_element求区间中的最小值(可自定义比较器)
max_element求区间中的最大值(可自定义比较器)
for_each对区间中的每个元素都做某种操作
count计算区间中等于某值的元素个数
count_if计算区间中符合某种条件的元素个数
find在区间中查找等于某值的元素
find_if在区间中查找符合某条件的元素
find_end在区间中查找另一个区间最后一次出现的位置(可自定义比较器)
find_first_of在区间中查找第一个出现在另一个区间中的元素 (可自定义比较器)
adjacent_find在区间中寻找第一次出现连续两个相等元素的位置(可自定义比较器)
search在区间中查找另一个区间第一次出现的位置(可自定义比较器)
search_n在区间中查找第一次出现等于某值的连续n个元素(可自定义比较器)
equal判断两区间是否相等(可自定义比较器)
mismatch逐个比较两个区间的元素,返回第一次发生不相等的两个元素的位置(可自定义比较器)
lexicographical_compare按字典序比较两个区间的大小(可自定义比较器)for_each
template<class InIt, class Fun> 
Fun for_each(InIt first, InIt last, Fun f);
对[first,last)中的每个元素 e ,执行 f(e) , 要求 f(e)不能改变e。count:
template<class InIt, class T> 
size_t count(InIt first, InIt last, const T& val);
计算[first,last) 中等于val的元素个数count_if 
template<class InIt, class Pred> 
size_t count_if(InIt first, InIt last, Pred pr);
计算[first,last) 中符合pr(e) == true 的元素 e的个数min_element:
template<class FwdIt> 
FwdIt min_element(FwdIt first, FwdIt last); 
返回[first,last) 中最小元素的迭代器,以 “< ”作比较器。最小指没有元素比它小,而不是它比别的不同元素都小因为即便a!= b, a<b 和b<a有可能都不成立max_element:
template<class FwdIt> 
FwdIt max_element(FwdIt first, FwdIt last); 
返回[first,last) 中最大元素(它不小于任何其他元素,但不见得其他不同元素都小于它)的迭代器,以 “< ”作比较器。find
template<class InIt, class T> 
InIt find(InIt first, InIt last, const T& val);
返回区间 [first,last) 中的迭代器 i ,使得 * i == valfind_if
template<class InIt, class Pred> 
InIt find_if(InIt first, InIt last, Pred pr);
返回区间 [first,last) 中的迭代器 i, 使得 pr(*i) == true
#include <iostream>
#include <algorithm>
using namespace std;
class A {
public: int n;A(int i):n(i) { }
};
bool operator<( const A & a1, const A & a2) {cout << "< called,a1="<< a1.n << " a2=" << a2.n << endl;if( a1.n == 3 && a2.n == 7)return true;return false;
}
int main() {A aa[] = { 3,5,7,2,1};cout << min_element(aa,aa+5)->n << endl;cout << max_element(aa,aa+5)->n << endl;return 0;
}
< called,a1=5 a2=3
< called,a1=7 a2=3
< called,a1=2 a2=3
< called,a1=1 a2=3
3
< called,a1=3 a2=5
< called,a1=3 a2=7
< called,a1=7 a2=2
< called,a1=7 a2=1
7

2.变值算法

此类算法会修改源区间或目标区间元素的值。值被修改的那个区间,不可以是属于关联容器的。

for_each对区间中的每个元素都做某种操作
copy复制一个区间到别处
copy_backward复制一个区间到别处,但目标区前是从后往前被修改的
transform将一个区间的元素变形后拷贝到另一个区间
swap_ranges交换两个区间内容
fill用某个值填充区间
fill_n用某个值替换区间中的n个元素
generate用某个操作的结果填充区间
generate_n用某个操作的结果替换区间中的n个元素
replace将区间中的某个值替换为另一个值
replace_if将区间中符合某种条件的值替换成另一个值
replace_copy将一个区间拷贝到另一个区间,拷贝时某个值要换成新值拷过去
replace_copy_if将一个区间拷贝到另一个区间,拷贝时符合某条件的值要换成新值拷过去transform
template<class InIt, class OutIt, class Unop> 
OutIt transform(InIt first, InIt last, OutIt x, Unop uop); 
对[first,last)中的每个迭代器 I ,执行 uop( * I ) ; 并将结果依次放入从 x 开始的地方。要求 uop( * I ) 不得改变 * I 的值。
本模板返回值是个迭代器,即 x + (last-first)x 可以和 first相等。
#include <vector>
#include <iostream>
#include <numeric>
#include <list>
#include <algorithm>
#include <iterator>using namespace std;class CLessThen9 {
public:bool operator()(int n) { return n < 9; }
};void outputSquare(int value)
{cout << value * value << " ";
}int calculateCube(int value)
{return value * value * value;
}int main() {const int SIZE = 10;int a1[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};int a2[] = {100, 2, 8, 1, 50, 3, 8, 9, 10, 2};vector<int> v(a1, a1 + SIZE);ostream_iterator<int> output(cout, " ");random_shuffle(v.begin(), v.end());cout << endl << "1) ";copy(v.begin(), v.end(), output);copy(a2, a2 + SIZE, v.begin());cout << endl << "2)";cout << count(v.begin(), v.end(), 8);cout << endl << "3)";cout << count_if(v.begin(), v.end(), CLessThen9());cout << endl << "4)";cout << *(min_element(v.begin(), v.end()));cout << endl << "5)";cout << *(max_element(v.begin(), v.end()));cout << endl << "6) ";cout << accumulate(v.begin(), v.end(), 0);//求和cout << endl << "7) ";for_each(v.begin(), v.end(), outputSquare);vector<int> cubes(SIZE);transform(a1, a1 + SIZE, cubes.begin(), calculateCube);cout << endl << "8) ";copy(cubes.begin(), cubes.end(), output);return 0;
}
1) 9 2 10 3 1 6 8 4 5 7
22
36
41
5100
6) 193
7) 10000 4 64 1 2500 9 64 81 100 4
8) 1 8 27 64 125 216 343 512 729 1000

4.删除算法

删除算法会删除一个容器里的某些元素。这里所说的“删除”,并不会使容器里的元素减少,其工作过程
是:将所有应该被删除的元素看做空位子,然后用留下的元素从后往前移,依次去填空位子。元素往前移后,它原来的位置也就算是空位子,也应由后面的留下的元素来填上。最后,没有被填上的空位子,维持其原来的值不变。删除算法不应作用于关联容器。

remove删除区间中等于某个值的元素
remove_if删除区间中满足某种条件的元素
remove_copy拷贝区间到另一个区间。等于某个值的元素不拷贝
remove_copy_if拷贝区间到另一个区间。符合某种条件的元素不拷贝
unique删除区间中连续相等的元素,只留下一个(可自定义比较器)
unique_copy拷贝区间到另一个区间。连续相等的元素,只拷贝第一个到目标区间 (可自定义比较器)uniquetemplate<class FwdIt> FwdIt unique(FwdIt first, FwdIt last); 用 == 比较是否等template<class FwdIt, class Pred> FwdIt unique(FwdIt first, FwdIt last, Pred pr);用 pr 比较是否等
对[first,last) 这个序列中连续相等的元素,只留下第一个。
返回值是迭代器,指向元素删除后的区间的最后一个元素的后面。
int main()
{int a[5] = { 1,2,3,2,5};int b[6] = { 1,2,3,2,5,6};ostream_iterator<int> oit(cout,",");int * p = remove(a,a+5,2);cout << "1) ";copy(a,a+5,oit);cout << endl;//输出 1) 1,3,5,2,5,cout << "2) " << p - a << endl; //输出 2) 3vector<int> v(b,b+6);remove(v.begin(),v.end(),2);cout << "3) ";copy(v.begin(),v.end(),oit);cout << endl;//输出 3) 1,3,5,6,5,6,cout << "4) "; cout << v.size() << endl;//v中的元素没有减少,输出 4) 6return 0;
}
1) 1,3,5,2,5,
2) 3
3) 1,3,5,6,5,6,
4) 6

5.变序算法

变序算法改变容器中元素的顺序,但是不改变元素的值。变序算法不适用于关联容器。此类算法复杂度都是O(n)的。

reverse颠倒区间的前后次序
reverse_copy把一个区间颠倒后的结果拷贝到另一个区间,源区间不变
rotate将区间进行循环左移
rotate_copy将区间以首尾相接的形式进行旋转后的结果拷贝到另一个区间,源区间不变
next_permutation将区间改为下一个排列(可自定义比较器)
prev_permutation将区间改为上一个排列(可自定义比较器)
random_shuffle随机打乱区间内元素的顺序
partition把区间内满足某个条件的元素移到前面,不满足该条件的移到后面
stable_patition把区间内满足某个条件的元素移到前面,不满足该条件的移到后面。而且对这两部分元素,分别保持它们原来的先后次序不变
int main()
{string str = "231";char szStr[] = "324";while (next_permutation(str.begin(), str.end())){cout << str << endl;}cout << "****" << endl;while (next_permutation(szStr,szStr + 3)){cout << szStr << endl;}sort(str.begin(),str.end());cout << "****" << endl;while (next_permutation(str.begin(), str.end())){cout << str << endl;}return 0;
}
312
321
****
342
423
432
****
132
213
231
312
321
int main()
{int a[] = { 8,7,10 };list<int> ls(a , a + 3);while( next_permutation(ls.begin(),ls.end())){list<int>::iterator i;for( i = ls.begin();i != ls.end(); ++i)cout << * i << " ";cout << endl;}
}
8 10 7
10 7 8
10 8 7

6.排序算法

排序算法比前面的变序算法复杂度更高,一般是O(n×log(n))。排序算法需要随机访问迭代器的支持,因而不适用于关联容器和list。

  1. sort 实际上是快速排序,时间复杂度 O(n*log(n));平均性能最优。但是最坏的情况下,性能可能非常差。

  2. 如果要保证“最坏情况下”的性能,那么可以使用stable_sort。

  3. stable_sort 实际上是归并排序,特点是能保持相等元素之间的先后次序。

  4. 在有足够存储空间的情况下,复杂度为 n * log(n),否则复杂度为 n * log(n) * log(n)。

  5. stable_sort 用法和 sort相同。

  6. 排序算法要求随机存取迭代器的支持,所以list 不能使用排序算法,要使用list::sort。

     sort将区间从小到大排序(可自定义比较器)。stable_sort将区间从小到大排序,并保持相等元素间的相对次序(可自定义比较器)。partial_sort对区间部分排序,直到最小的n个元素就位(可自定义比较器)。partial_sort_copy将区间前n个元素的排序结果拷贝到别处。源区间不变(可自定义比较器)。nth_element对区间部分排序,使得第n小的元素(n从0开始算)就位,而且比它小的都在它前面,比它大的都在它后面(可自定义比较器)。make_heap使区间成为一个“堆”(可自定义比较器)。push_heap将元素加入一个是“堆”区间(可自定义比较器)。pop_heap从 “堆”区间删除堆顶元素(可自定义比较器)。sort_heap将一个“堆”区间进行排序,排序结束后,该区间就是普通的有序区间,不再是 “堆”了(可自定义比较器)。partial_sort : 部分排序,直到 前 n 个元素就位即可。nth_element : 排序,直到第 n个元素就位,并保证比第n个元素小的元素都在第 n 个元素之前即可。partition: 改变元素次序,使符合某准则的元素放在前面
    

    sort 快速排序:

     template<class RanIt> void sort(RanIt first, RanIt last); 按升序排序。判断x是否应比y靠前,就看 x < y 是否为truetemplate<class RanIt, class Pred>void sort(RanIt first, RanIt last, Pred pr);按升序排序。判断x是否应比y靠前,就看 pr(x,y) 是否为true
    
class MyLess {
public:bool operator()(int n1, int n2) {return (n1 % 10) < (n2 % 10);}
};int main() {int a[] = {14, 2, 9, 111, 78};sort(a, a + 5, MyLess());int i;for (i = 0; i < 5; i++)cout << a[i] << " ";cout << endl;sort(a, a + 5, greater<int>());for (i = 0; i < 5; i++)cout << a[i] << " ";
}
111 2 14 78 9
111 78 14 9 2

7. 堆排序

堆:一种二叉树,最大元素总是在堆顶上,二叉树中任何节点的子节点总是小于或等于父节点的值

  1. 什么是堆?
    n个记录的序列,其所对应的关键字的序列为{k0, k1, k2, …, kn-1},若有如下关系成立时,
    则称该记录序列构成一个堆。
    ki≥k2i+1且 ki≥k2i+2, 其中i=0, 1, …,
    例如,下面的关键字序列构成一个堆。
    96 83 27 38 11 9
    y r p d f b k a c
    堆排序的各种算法,如make_heap等,需要随机访问迭代器的支持。

  2. make_heap 函数模板

     template<class RanIt> void make_heap(RanIt first, RanIt last); 将区间 [first,last) 做成一个堆。用 < 作比较器template<class RanIt, class Pred> void make_heap(RanIt first, RanIt last, Pred pr);将区间 [first,last) 做成一个堆。用 pr 作比较器
    
  3. push_heap 函数模板

     template<class RanIt>void push_heap(RanIt first, RanIt last); template<class RanIt, class Pred> void push_heap(RanIt first, RanIt last, Pred pr); 
    

    在[first,last-1)已经是堆的情况下,该算法能将[first,last)变成堆,时间复杂度O(log(n))。
    往已经是堆的容器中添加元素,可以在每次 push_back 一个元素后,再调用 push_heap算法。

  4. pop_heap 函数模板
    取出堆中最大的元素

     template<class RanIt> void pop_heap(RanIt first, RanIt last); template<class RanIt, class Pred> void pop_heap(RanIt first, RanIt last, Pred pr);
    

    将堆中的最大元素,即 * first ,移到 last –1 位置,原 * (last –1 )被移到前面某个位置,并且移动后[first,last –1)仍然是个堆。要求原[first,last)就是个堆。
    复杂度 O(log(n))

8.有序区间算法

有序区间算法要求所操作的区间是已经从小到大排好序的,而且需要随机访问迭代器的支持。所以有序区间算法不能用于关联容器和list。

binary_search判断区间中是否包含某个元素。
includes判断是否一个区间中的每个元素,都在另一个区间中。
lower_bound查找最后一个不小于某值的元素的位置。
upper_bound查找第一个大于某值的元素的位置。
equal_range同时获取lower_bound和upper_bound。
merge合并两个有序区间到第三个区间。
set_union将两个有序区间的并拷贝到第三个区间
set_intersection将两个有序区间的交拷贝到第三个区间
set_difference将两个有序区间的差拷贝到第三个区间
set_symmetric_difference将两个有序区间的对称差拷贝到第三个区间
inplace_merge将两个连续的有序区间原地合并为一个有序区间binary_search 
折半查找,要求容器已经有序且支持随机访问迭代器,返回是否找到template<class FwdIt, class T>bool binary_search(FwdIt first, FwdIt last, const T& val); 上面这个版本,比较两个元素x,y 大小时, 看 x < ytemplate<class FwdIt, class T, class Pred> bool binary_search(FwdIt first, FwdIt last, const T& val, Pred pr);上面这个版本,比较两个元素x,y 大小时, 若 pr(x,y) 为true,则认为x小于ylower_bound:template<class FwdIt, class T> FwdIt lower_bound(FwdIt first, FwdIt last, const T& val); 
要求[first,last)是有序的,
查找[first,last)中的,最大的位置 FwdIt,使得[first,FwdIt) 中所有的元素都比 val 小upper_boundtemplate<class FwdIt, class T>FwdIt upper_bound(FwdIt first, FwdIt last, const T& val); 
要求[first,last)是有序的,
查找[first,last)中的,最小的位置 FwdIt,使得[FwdIt,last) 中所有的元素都比 val 大equal_rangetemplate<class FwdIt, class T> pair<FwdIt, FwdIt> equal_range(FwdIt first, FwdIt last, const T& val); 
要求[first,last)是有序的,
返回值是一个pair, 假设为 p, 则:
[first,p.first) 中的元素都比 val 小
[p.second,last)中的所有元素都比 val 大
p.first 就是lower_bound的结果
p.last 就是 upper_bound的结果mergetemplate<class InIt1, class InIt2, class OutIt> OutIt merge(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt x);用 < 作比较器template<class InIt1, class InIt2, class OutIt, class Pred> OutIt merge(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt x, Pred pr);用 pr 作比较器
把[first1,last1), [ first2,last2) 两个升序序列合并,形成第3 个升序序列,第3个升序序列以 x 开头。includestemplate<class InIt1, class InIt2> bool includes(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2);template<class InIt1, class InIt2, class Pred> bool includes(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, Pred pr);
判断 [first2,last2)中的每个元素,是否都在[first1,last1)中第一个用 <作比较器,第二个用 pr 作比较器, pr(x,y) == true说明 x,y相等。set_differencetemplate<class InIt1, class InIt2, class OutIt> OutIt set_difference(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt x); template<class InIt1, class InIt2, class OutIt, class Pred> OutIt set_difference(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt x, Pred pr);
求出[first1,last1)中,不在[first2,last2)中的元素,放到 从 x开始的地方。如果 [first1,last1) 里有多个相等元素不在[first2,last2)中,则这多个元素也都会被放入x代表的目标区间里。set_intersectiontemplate<class InIt1, class InIt2, class OutIt> OutIt set_intersection(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt x); template<class InIt1, class InIt2, class OutIt, class Pred> OutIt set_intersection(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt x, Pred pr);
求出[first1,last1)和[first2,last2)中共有的元素,放到从 x开始的地方。
若某个元素e 在[first1,last1)里出现 n1次,在[first2,last2)里出现n2次,则该元素在目标区间里出现min(n1,n2)次。set_symmetric_differencetemplate<class InIt1, class InIt2, class OutIt> OutIt set_symmetric_difference(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt x); template<class InIt1, class InIt2, class OutIt, class Pred> OutIt set_symmetric_difference(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt x, Pred pr);
把两个区间里相互不在另一区间里的元素放入x开始的地方。set_uniontemplate<class InIt1, class InIt2, class OutIt>OutIt set_union(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt x); 用<比较大小template<class InIt1, class InIt2, class OutIt, class Pred> OutIt set_union(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt x, Pred pr); 用 pr 比较大小
求两个区间的并,放到以 x开始的位置。
若某个元素e 在[first1,last1)里出现 n1次,在[first2,last2)里出现n2次,则该元素在目标区间里出现max(n1,n2)次。
bool Greater10(int n)
{return n > 10;
}int main() {const int SIZE = 10;int a1[] = { 2,8,1,50,3,100,8,9,10,2 };vector<int> v(a1,a1+SIZE);cout  << "0) ";for (vector<int>::iterator i = v.begin(); i !=v.end() ; ++i) {cout  << *i << "  ";}cout << endl;ostream_iterator<int> output(cout," ");vector<int>::iterator location;location = find(v.begin(),v.end(),10);if( location != v.end()) {cout << endl << "1) " << location - v.begin();}location = find_if( v.begin(),v.end(),Greater10);if( location != v.end())cout << endl << "2) " << location - v.begin();sort(v.begin(),v.end());if( binary_search(v.begin(),v.end(),9)) {cout << endl << "3) " << "9 found";}
}
0) 2  8  1  50  3  100  8  9  10  2
1) 8
2) 3
3) 9 found

9.bitset

template<size_t N>
class bitset 
{
….. 
};
实际使用的时候,N是个整型常数
如:
bitset<40> bst;
bst是一个由40位组成的对象,用bitset的函数可以方便地访问任
何一位。

bitset的成员函数:

bitset<N>& operator&=(const bitset<N>& rhs); 
bitset<N>& operator|=(const bitset<N>& rhs); 
bitset<N>& operator^=(const bitset<N>& rhs); 
bitset<N>& operator<<=(size_t num); 
bitset<N>& operator>>=(size_t num); 
bitset<N>& set(); //全部设成1
bitset<N>& set(size_t pos, bool val = true); //设置某位
bitset<N>& reset(); //全部设成0
bitset<N>& reset(size_t pos); //某位设成0
bitset<N>& flip(); //全部翻转
bitset<N>& flip(size_t pos); //翻转某位
reference operator[](size_t pos); //返回对某位的引用
bool operator[](size_t pos) const; //判断某位是否为1
reference at(size_t pos); 
bool at(size_t pos) const; 
unsigned long to_ulong() const; //转换成整数
string to_string() const; //转换成字符串
size_t count() const; //计算1的个数
size_t size() const; 
bool operator==(const bitset<N>& rhs) const; 
bool operator!=(const bitset<N>& rhs) const;
bool test(size_t pos) const; //测试某位是否为 1
bool any() const; //是否有某位为1 
bool none() const; //是否全部为0
bitset<N> operator<<(size_t pos) const; 
bitset<N> operator>>(size_t pos) const; 
bitset<N> operator~(); 
static const size_t bitset_size = N; 
注意:第0位在最右边

五、STL中的“大”、“小”和“相等”

1.STL中“大”“小” 的概念

  1. 关联容器内部的元素是从小到大排序的
  2. 有些算法要求其操作的区间是从小到大排序的,称为“有序区间算法”
    例:binary_search
  3. 有些算法会对区间进行从小到大排序,称为“排序算法”
    例: sort
  4. 还有一些其他算法会用到“大”,“小”的概念
  5. 使用STL时,在缺省的情况下,以下三个说法等价:
    1) x比y小
    2) 表达式“x<y”为真
    3) y比x大

2.STL中“相等”的概念

  1. 有时,“x和y相等”等价于“x==y为真”
    例:在未排序的区间上进行的算法,如顺序查找find
    ……
  2. 有时“x和y相等”等价于“x小于y和y小于x同时为假”
    例:
    有序区间算法,如binary_search
    关联容器自身的成员函数find
    ……
class A {int v;public:A(int n):v(n) { }bool operator < ( const A & a2) const {//必须为常量成员函数cout << v << "<" << a2.v << "?" << endl;return false;}bool operator ==(const A & a2) const {cout << v << "==" << a2.v << "?" << endl;return v == a2.v;}
};
int main()
{A a [] ={ A(1),A(2),A(3),A(4),A(5) };cout << binary_search(a,a+4,A(9));//折半查找return 0;
}
3<9?
2<9?
1<9?
9<1?
1

六、使用方法

1.vector

vector 示例程序

#include "iostream"
#include "vector"
using namespace std;
template<class T>
void PrintVector( T s, T e)
{for(; s != e; ++s)cout << * s << " ";cout << endl;
}int main() {int a[5] = { 1,2,3,4,5 };vector<int> v(a,a+5); //将数组a的内容放入vcout << "1) " << v.end() - v.begin() << endl;//两个随机迭代器可以相减,输出 1) 5cout << "2) "; PrintVector(v.begin(),v.end());//2) 1 2 3 4 5v.insert(v.begin() + 2, 13); //在begin()+2位置插入 13cout << "3) "; PrintVector(v.begin(),v.end());//3) 1 2 13 3 4 5v.erase(v.begin() + 2); //删除位于 begin() + 2的元素cout << "4) "; PrintVector(v.begin(),v.end());//4) 1 2 3 4 5vector<int> v2(4,100); //v2 有4个元素,都是100v2.insert(v2.begin(),v.begin()+ 1,v.begin()+3);//将v的一段插入v2开头cout << "5) v2: "; PrintVector(v2.begin(),v2.end());//5) v2: 2 3 100 100 100 100v.erase(v.begin() + 1, v.begin() + 3);//删除 v 上的一个区间,即 2,3cout << "6) "; PrintVector(v.begin(),v.end());//6) 1 4 5return 0;
}
1) 5
2) 1 2 3 4 5
3) 1 2 13 3 4 5
4) 1 2 3 4 5
5) v2: 2 3 100 100 100 100
6) 1 4 5
#include <iostream>
#include "vector"
#include "algorithm"
using namespace std;int main() { //find算法示例int array[10] = {10,20,30,40};vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>::iterator p;p = find(v.begin(),v.end(),3);if( p != v.end())cout << * p << endl; //输出3p = find(v.begin(),v.end(),9);if( p == v.end())cout << "not found " << endl;p = find(v.begin()+1,v.end()-2,1);//整个容器:[1,2,3,4], 查找区间:[2,3)if( p != v.end())cout << * p << endl;int * pp = find( array,array+4,20);//数组名是迭代器cout << * pp << endl;
}

2.deque

所有适用于 vector的操作都适用于 deque。
deque还有 push_front(将元素插入到前面) 和pop_front(删除最前面的元素)操作,复杂度是O(1)

3.双向链表list

  1. 在任何位置插入删除都是常数时间,不支持随机存取。

  2. 除了具有所有顺序容器都有的成员函数以外,还支持8个成员函数:

     push_front: 在前面插入pop_front: 删除前面的元素sort: 排序 ( list 不支持 STL 的算法 sort)remove: 删除和指定值相等的所有元素unique: 删除所有和前一个元素相同的元素(要做到元素不重复,则unique之前还需要 sort)merge: 合并两个链表,并清空被合并的那个reverse: 颠倒链表splice: 在指定位置前面插入另一链表中的一个或多个元素,并在另一链表中删除被插入的元素
    
#include <list>
#include <iostream>
#include <algorithm>
using namespace std;class A {
private:int n;
public:A( int n_ ) { n = n_; }friend bool operator<( const A & a1, const A & a2);friend bool operator==( const A & a1, const A & a2);friend ostream & operator <<( ostream & o, const A & a);
};
bool operator<( const A & a1, const A & a2) {return a1.n < a2.n;
}
bool operator==( const A & a1, const A & a2) {return a1.n == a2.n;
}
ostream & operator <<( ostream & o, const A & a) {o << a.n;return o;
}template <class T>
void PrintList(const list<T> & lst) {
//不推荐的写法,还是用两个迭代器作为参数更好int tmp = lst.size();if( tmp > 0 ) {typename list<T>::const_iterator i;i = lst.begin();for( i = lst.begin();i != lst.end(); i ++)cout << * i << ",";}
}// typename用来说明 list<T>::const_iterator是个类型//在vs中不写也可以int main() {list<A> lst1,lst2;lst1.push_back(1);lst1.push_back(3);lst1.push_back(2);lst1.push_back(4);lst1.push_back(2);lst2.push_back(10);lst2.push_front(20);lst2.push_back(30);lst2.push_back(30);lst2.push_back(30);lst2.push_front(40);lst2.push_back(40);cout << "1) "; PrintList( lst1); cout << endl;
// 1) 1,3,2,4,2,cout << "2) "; PrintList( lst2); cout << endl;
// 2) 40,20,10,30,30,30,40,lst2.sort();cout << "3) "; PrintList( lst2); cout << endl;
//3) 10,20,30,30,30,40,40,lst2.pop_front();cout << "4) "; PrintList( lst2); cout << endl;
//4) 20,30,30,30,40,40,lst1.remove(2); //删除所有和A(2)相等的元素cout << "5) "; PrintList( lst1); cout << endl;
//5) 1,3,4,lst2.unique(); //删除所有和前一个元素相等的元素cout << "6) "; PrintList( lst2); cout << endl;
//6) 20,30,40,lst1.merge (lst2); //合并 lst2到lst1并清空lst2cout << "7) "; PrintList( lst1); cout << endl;
//7) 1,3,4,20,30,40,cout << "8) "; PrintList( lst2); cout << endl;
//8)lst1.reverse();cout << "9) "; PrintList( lst1); cout << endl;
//9) 40,30,20,4,3,1,lst2.push_back (100);lst2.push_back (200);lst2.push_back (300);lst2.push_back (400);list<A>::iterator p1,p2,p3;p1 = find(lst1.begin(),lst1.end(),3);p2 = find(lst2.begin(),lst2.end(),200);p3 = find(lst2.begin(),lst2.end(),400);lst1.splice(p1,lst2,p2, p3);
//将[p2,p3)插入p1之前,并从lst2中删除[p2,p3)cout << "10) "; PrintList( lst1); cout << endl;
//10) 40,30,20,4,200,300,3,1,cout << "11) "; PrintList( lst2); cout << endl;
//11) 100,400,return 0;
}

4.set和multiset

set, multiset, map, multimap

  1. 内部元素有序排列,新元素插入的位置取决于它的值,查找速度快。

  2. 除了各容器都有的函数外,还支持以下成员函数:

     find: 查找等于某个值 的元素(x小于y和y小于x同时不成立即为相等)lower_bound : 查找某个下界upper_bound : 查找某个上界equal_range : 同时查找上界和下界count :计算等于某个值的元素个数(x小于y和y小于x同时不成立即为相等)insert: 用以插入一个元素或一个区间
    

pair 模板
map/multimap容器里放着的都是pair模版类的对象,且按first从小到大排序

template<class _T1, class _T2>
struct pair
{typedef _T1 first_type;typedef _T2 second_type;_T1 first;_T2 second;pair(): first(), second() { }pair(const _T1& __a, const _T2& __b): first(__a), second(__b) { }template<class _U1, class _U2>pair(const pair<_U1, _U2>& __p): first(__p.first), second(__p.second) { }
};

示例:

int main(){pair<int,int> p(pair<double,double>(5.5,4.6));cout<< p.first << "   " << p.second << endl;return 0;
}

multiset

template<class Key, class Pred = less<Key>, 
class A = allocator<Key> >
class multiset { …… };
  1. Pred类型的变量决定了multiset 中的元素,“一个比另一个小”是怎么定义的。
    multiset运行过程中,比较两个元素x,y的大小的做法,就是生成一个 Pred类型的
    变量,假定为 op,若表达式op(x,y) 返回值为true,则 x比y小。
    Pred的缺省类型是 less。
  2. less 模板的定义:
template<class T> 
struct less : public binary_function<T, T, bool> 
{ bool operator()(const T& x, const T& y) { return x < y ; } const; };
//less模板是靠 < 来比较大小的
  1. multiset的成员函数

     iterator find(const T & val);在容器中查找值为val的元素,返回其迭代器。如果找不到,返回end()。iterator insert(const T & val); 将val插入到容器中并返回其迭代器。void insert( iterator first,iterator last); 将区间[first,last)插入容器。int count(const T & val); 统计有多少个元素的值和val相等。iterator lower_bound(const T & val);查找一个最大的位置 it,使得[begin(),it) 中所有的元素都比 val 小。iterator upper_bound(const T & val);查找一个最小的位置 it,使得[it,end()) 中所有的元素都比 val 大。pair<iterator,iterator> equal_range(const T & val);同时求得lower_bound和upper_bound。iterator erase(iterator it);删除it指向的元素,返回其后面的元素的迭代器(Visual studio 2010上如此,但是在C++标准和Dev C++中,返回值不是这样)。
    
#include <set> //使用multiset须包含此文件template<class T>
void Print(T first, T last) {for (; first != last; ++first)cout << *first << " ";cout << endl;
}class A {
private:int n;
public:A(int n_) { n = n_; }friend bool operator<(const A &a1, const A &a2) { return a1.n < a2.n; }friend ostream &operator<<(ostream &o, const A &a2) {o << a2.n;return o;}friend class MyLess;
};struct MyLess {bool operator()(const A &a1, const A &a2)
//按个位数比大小{ return (a1.n % 10) < (a2.n % 10); }
};typedef multiset<A> MSET1; //MSET1用 "<"比较大小
typedef multiset<A, MyLess> MSET2; //MSET2用 MyLess::operator()比较大小int main() {const int SIZE = 6;A a[SIZE] = {4, 22, 19, 8, 33, 40};MSET1 m1;m1.insert(a, a + SIZE);m1.insert(22);cout << "1) " << m1.count(22) << endl; //输出 1) 2cout << "2) ";Print(m1.begin(), m1.end()); //输出 2) 4 8 19 22 22 33 40//m1元素:4 8 19 22 22 33 40MSET1::iterator pp = m1.find(19);if (pp != m1.end()) //条件为真说明找到cout << "found" << endl;//本行会被执行,输出 foundcout << "3) ";cout << *m1.lower_bound(22) << ","<< *m1.upper_bound(22) << endl;
//输出 3) 22,33pp = m1.erase(m1.lower_bound(22), m1.upper_bound(22));
//pp指向被删元素的下一个元素cout << "4) ";Print(m1.begin(), m1.end()); //输出 4) 4 8 19 33 40cout << "5) ";cout << *pp << endl; //输出 5) 33MSET2 m2; // m2里的元素按n的个位数从小到大排m2.insert(a, a + SIZE);cout << "6) ";Print(m2.begin(), m2.end()); //输出 6) 40 22 33 4 8 19return 0;
}
1) 2
2) 4 8 19 22 22 33 40
found
3) 22,33
4) 4 8 19 33 40
5) 33
6) 40 22 33 4 8 19

set
插入set中已有的元素时,忽略插入。

template<class Key, class Pred = less<Key>, 
class A = allocator<Key> > 
class set {}

示例:

#include "set"
int main() {typedef set<int>::iterator IT;int a[5] = { 3,4,6,1,2 };set<int> st(a,a+5); // st里是 1 2 3 4 6pair< IT,bool> result;result = st.insert(5); // st变成 1 2 3 4 5 6if( result.second ) //插入成功则输出被插入元素cout << * result.first << " inserted" << endl; //输出: 5 insertedif( st.insert(5).second )cout << * result.first << endl;elsecout << * result.first << " already exists" << endl; //输出 5 already existspair<IT,IT> bounds = st.equal_range(4);cout << * bounds.first << "," << * bounds.second ; //输出:4,5return 0;
}

5.map和multimap

  1. multimap
template<class Key, class T, class Pred = less<Key>,
class A = allocator<T> > 
class multimap {.
typedef pair<const Key, T> value_type; 
…….
}; //Key 代表关键字的类型
	multimap中的元素由 <关键字,值>组成,每个元素是一个pair对象,关键字就是first成员变量,其类型是Keymultimap 中允许多个元素的关键字相同。元素按照first成员变量从小到大排列,缺省情况下用 less<Key> 定义关键字的“小于”关系。

示例:

#include <iostream>
#include <map>
using namespace std;
int main() {typedef multimap<int,double,less<int> > mmid;mmid pairs;cout << "1) " << pairs.count(15) << endl;pairs.insert(mmid::value_type(15,2.7));//typedef pair<const Key, T> value_type;pairs.insert(mmid::value_type(15,99.3));cout << "2) " << pairs.count(15) << endl; //求关键字等于某值的元素个数pairs.insert(mmid::value_type(30,111.11));pairs.insert(mmid::value_type(10,22.22));pairs.insert(mmid::value_type(25,33.333));pairs.insert(mmid::value_type(20,9.3));for( mmid::const_iterator i = pairs.begin();i != pairs.end() ;i ++ )cout << "(" << i->first << "," << i->second << ")" << ",";
}
1) 0
2) 2
(10,22.22),(15,2.7),(15,99.3),(20,9.3),(25,33.333),(30,111.11),
  1. map
template<class Key, class T, class Pred = less<Key>,
class A = allocator<T> > 
class map {.typedef pair<const Key, T> value_type; …….
};
	map 中的元素都是pair模板类对象。关键字(first成员变量)各不相同。元素按照关键字从小到大排列,缺省情况下用 less<Key>,即“<” 定义“小于”。

map的[ ]成员函数

	若pairs为map模版类的对象,pairs[key]返回对关键字等于key的元素的值(second成员变量)的引用。若没有关键字为key的元素,则会往pairs里插入一个关键字为key的元素,其值用无参构造函数初始化,并返回其值的引用.如:map<int,double> pairs;则pairs[50] = 5; 会修改pairs中关键字为50的元素,使其值变成5。若不存在关键字等于50的元素,则插入此元素,并使其值变为5。

示例:

#include <iostream>
#include <map>
using namespace std;
template <class Key,class Value>
ostream & operator <<( ostream & o, const pair<Key,Value> & p)
{o << "(" << p.first << "," << p.second << ")";return o;
}
int main() {typedef map<int, double, less<int> > mmid;mmid pairs;cout << "1) " << pairs.count(15) << endl;   //0pairs.insert(mmid::value_type(15, 2.7));pairs.insert(make_pair(15, 99.3)); //make_pair生成一个pair对象 //添加失败cout << "2) " << pairs.count(15) << endl;pairs.insert(mmid::value_type(20, 9.3));mmid::iterator i;cout << "3) ";for (i = pairs.begin(); i != pairs.end(); i++)cout << *i << ",";cout << endl;cout << "4) ";int n = pairs[40];//如果没有关键字为40的元素,则插入一个for (i = pairs.begin(); i != pairs.end(); i++)cout << *i << ",";cout << endl;cout << "5) ";pairs[15] = 6.28; //把关键字为15的元素值改成6.28for (i = pairs.begin(); i != pairs.end(); i++)cout << *i << ",";
}
1) 0
2) 1
3) (15,2.7),(20,9.3),
4) (15,2.7),(20,9.3),(40,0),
5) (15,6.28),(20,9.3),(40,0),

6.stack

  1. stack 是后进先出的数据结构,只能插入,删除,访问栈顶的元素。
  2. 可用 vector, list, deque来实现。缺省情况下,用deque实现。
    用 vector和deque实现,比用list实现性能好。
template<class T, class Cont = deque<T> > 
class stack {..
};

stack 上可以进行以下操作:

	push 插入元素pop 弹出元素top 返回栈顶元素的引用

7.queue

  1. 和stack 基本类似,可以用 list和deque实现。缺省情况下用deque实现。
template<class T, class Cont = deque<T> > 
class queue {
……
};
  1. 同样也有push, pop, top函数。
    但是push发生在队尾;pop, top发生在队头。先进先出。
  2. 有 back成员函数可以返回队尾元素的引用

7.priority_queue

template <class T, class Container = vector<T>,
class Compare = less<T> > 
class priority_queue;
  1. 和 queue类似,可以用vector和deque实现。缺省情况下用vector实现。
  2. priority_queue 通常用堆排序技术实现,保证最大的元素总是在最前面。即执行pop操作时,删除的是最大的元素;执行top操作时,返回的是最大元素的常引用。默认的元素比较器是less。
  3. push、pop 时间复杂度O(logn)
  4. top()时间复杂度O(1)
#include <queue>
#include <iostream>
using namespace std;
int main()
{priority_queue<double> pq1;pq1.push(3.2); pq1.push(9.8); pq1.push(9.8); pq1.push(5.4);while( !pq1.empty() ) {cout << pq1.top() << " ";pq1.pop();} //上面输出 9.8 9.8 5.4 3.2cout << endl;priority_queue<double,vector<double>,greater<double> > pq2;pq2.push(3.2); pq2.push(9.8); pq2.push(9.8); pq2.push(5.4);while( !pq2.empty() ) {cout << pq2.top() << " ";pq2.pop();}//上面输出 3.2 5.4 9.8 9.8return 0;
}

8.容器适配器的元素个数

stack,queue,priority_queue 都有

empty() 成员函数用于判断适配器是否为空
size() 成员函数返回适配器中元素个数

七、函数对象

1.定义

是个对象,但是用起来看上去象函数调用,实际上也执行了函数调用。

class CMyAverage {
public:double operator()( int a1, int a2, int a3 ) {//重载 () 运算符return (double)(a1 + a2+a3) / 3;}
};int main(){CMyAverage average; //函数对象cout << average(3,2,3); // average.operator()(3,2,3) 用起来看上去象函数调用return 0;
}

2.函数对象的应用

STL里有以下模板:

template<class InIt, class T, class Pred> 
T accumulate(InIt first, InIt last, T val, Pred pr);

pr 就是个函数对象。对[first,last)中的每个迭代器 I, 执行 val = pr(val,* I) ,返回最终的val。
Pr也可以是个函数。

#include <iostream>
#include <vector>
#include <numeric>
using namespace std;int sumSquares( int total, int value){ return total + value * value; }template <class T>
void PrintInterval(T first, T last)
{ //输出区间[first,last)中的元素for( ; first != last; ++ first)cout << * first << " ";cout << endl;
}template<class T>
class SumPowers
{
private:int power;
public:SumPowers(int p):power(p) { }const T operator() ( const T & total,const T & value){ //计算 value的power次方,加到total上T v = value;for( int i = 0;i < power - 1; ++ i)v = v * value;return total + v;}
};
int main()
{const int SIZE = 10;int a1[] = { 1,2,3,4,5,6,7,8,9,10 };vector<int> v(a1,a1+SIZE);cout << "1) "; PrintInterval(v.begin(),v.end());int result = accumulate(v.begin(),v.end(),0,sumSquares);cout << "2) 平方和:" << result << endl;result =accumulate(v.begin(),v.end(),0,SumPowers<int>(3));cout << "3) 立方和:" << result << endl;result =accumulate(v.begin(),v.end(),0,SumPowers<int>(4));cout << "4) 4次方和:" << result;return 0;
}
1) 1 2 3 4 5 6 7 8 9 10
2) 平方和:385
3) 立方和:3025
4) 4次方和:25333

STL 的 里还有以下函数对象类模板:
equal_to
greater
less …….
这些模板可以用来生成函数对象

3.greater 函数对象类模板

template<class T> 
struct greater : public binary_function<T, T, bool> { bool operator()(const T& x, const T& y) const {return x > y;}
};
//binary_function定义:
template<class Arg1, class Arg2, class Result> 
struct binary_function { typedef Arg1 first_argument_type;typedef Arg2 second_argument_type; typedef Result result_type; 
};

应用:

  1. list 有两个sort函数,前面例子中看到的是不带参数的sort函数,它将list中的元素按 < 规定的比较方法 升序排列。
  2. list还有另一个sort函数:
template <class T2>
void sort(T2 op);

可以用 op来比较大小,即 op(x,y) 为true则认为x应该排在前面。

#include <list>
#include <iostream>
#include <iterator>
using namespace std;
class MyLess {
public:bool operator()( const int & c1, const int & c2 ){return (c1 % 10) < (c2 % 10);}
};int main()
{ const int SIZE = 5;int a[SIZE] = {5,21,14,2,3};list<int> lst(a,a+SIZE);lst.sort(MyLess());ostream_iterator<int> output(cout,",");copy( lst.begin(),lst.end(),output); cout << endl;//本句进行降序排序lst.sort(greater<int>()); //greater<int>()是个对象copy( lst.begin(),lst.end(),output);cout << endl;return 0;
}
21,2,3,14,5,
21,14,5,3,2,

4.引入函数对象后,STL中的“大”,“小”关系

关联容器和STL中许多算法,都是可以自定义比较器的。在自定义了比较器op的情况下,以下三种说法是等价的:

	1) x小于y2) op(x,y)返回值为true3) y大于x

比较规则的注意事项:

struct 结构名
{bool operator()( const T & a1,const T & a2) {//若a1应该在a2前面,则返回true。//否则返回false。}
};
  1. 排序规则返回 true,意味着 a1 必须在 a2 前面,返回 false,意味着 a1 并非必须在 a2 前面
  2. 排序规则的写法,不能造成比较 a1,a2 返回 true ,比较 a2,a1 也返回 true
    否则sort会 runtime error
  3. 比较 a1,a2 返回 false 比较 a2,a1 也返回 false,则没有问题

总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/74043.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++11并发与多线程笔记(11) std::atomic续谈、std::async深入谈

C11并发与多线程笔记&#xff08;11&#xff09; std::atomic续谈、std::async深入谈 1、std::atomic续谈2、std::async深入理解2.1 std::async参数详述2.2 std::async和std::thread()区别&#xff1a;2.3 async不确定性问题的解决 1、std::atomic续谈 #include <iostream&…

视频汇聚集中存储EasyCVR平台调用iframe地址视频无法播放,该如何解决?

安防监控视频汇聚平台EasyCVR基于云边端一体化架构&#xff0c;具有强大的数据接入、处理及分发能力&#xff0c;可提供视频监控直播、云端录像、视频云存储、视频集中存储、视频存储磁盘阵列、录像检索与回看、智能告警、平台级联、云台控制、语音对讲、AI算法中台智能分析无缝…

leetcode:1668. 最大重复子字符串(python3解法)

难度&#xff1a;简单 给你一个字符串 sequence &#xff0c;如果字符串 word 连续重复 k 次形成的字符串是 sequence 的一个子字符串&#xff0c;那么单词 word 的 重复值为 k 。单词 word 的 最大重复值 是单词 word 在 sequence 中最大的重复值。如果 word 不是 sequence 的…

No view found for id 0x7f0901c3 for fragment解决以及线上bug排查技巧

情景再现 开发这么久&#xff0c;不知道你们是否也经历过这样的情况&#xff0c;测试或者用户&#xff0c;反馈app闪退&#xff0c;结果你自己打开开发工具&#xff0c;去调试&#xff0c;一切正常&#xff0c;然后闪退还是存在&#xff0c;只是在开发环境中不能重现。这种情况…

UML图绘制 -- 类图

1.类图的画法 类 整体是个矩形&#xff0c;第一层类名&#xff0c;第二层属性&#xff0c;第三层方法。 &#xff1a;public- : private# : protected空格: 默认的default 对应的类写法。 public class Student {public String name;public Integer age;protected I…

如何将常用的jdbc方法封装起来???

你是否还在为每次新建项目连接数据库而烦恼&#xff1f;&#xff1f;&#xff1f;&#xff08;教你一次代码&#xff0c;简单完成每次连接&#xff09; 1.建立maven项目 还没下载安装或者不会建立maven项目的可以看这里哦&#xff1a;maven的下载安装与配置环境变量&#xff0…

【探索Linux】—— 强大的命令行工具 P.6(调试器-gdb、项目自动化构建工具-make/Makefile)

阅读导航 前言一、什么是调试器二、详解 GDB - 调试器1.使用前提2.经常使用的命令3.使用小技巧 三、项目自动化构建工具 - make/Makefile1. make命令⭕语法⭕常用选项⭕常用操作⭕make命令的工作原理⭕make命令的优势&#xff1a; 2.Makefile文件⭕Makefile的基本结构⭕Makefil…

React 生态应用 - React Router(2)

目录 RouteProps Route参数 重定向Redirect【v5】&& 【v6实现】 导航的处理 练习 使用随堂demo实现一个简单的鉴权&#xff1a;当前用户是admin的时候&#xff0c;可以访问所有菜单&#xff1b;当前用户是user的时候&#xff0c;无法访问admin页面&#xff08;用…

WSL ubuntu 20.04 安装python3

WSL ubuntu 20.04 安装python3 直接通过命令行安装python sudo apt-get install python3 在/usr/bin目录下查看所有python版本 同时需要在系统路径中加入软链接&#xff0c;将默认的python定向到python3上&#xff1a; sudo ln -s /usr/bin/python3.6 /usr/bin/python

PostgreSql 备份恢复

一、概述 数据库备份一般可分为物理备份和逻辑备份&#xff0c;其中物理备份又可分为物理冷备和物理热备&#xff0c;下面就各种备份方式进行详细说明&#xff08;一般情况下&#xff0c;生产环境采取的定时物理热备逻辑备份的方式&#xff0c;均是以下述方式为基础进一步研发编…

修复由于找不到vcruntime140.dll,无法继续执行代码的问题方法

提示“由于找不到 VCRUNTIME140.dll&#xff0c;无法继续执行代码。重新安装程序可能会解决此问题。”&#xff0c;这一般是什么原因导致了这个问题&#xff0c;我们要如何解决&#xff1f; 下面分享一下由于找不到vcruntime140.dll无法继续执行代码的解决方法。 解决方法&…

vue项目使用qrcodejs2遇到Cannot read property ‘appendChild‘ of null

这个问题是节点还没创建渲染完就读取节点&#xff0c;这个时候应该先让节点渲染完成在生成&#xff0c;解决方法有以下两种 1、使用$nextTick&#xff08;&#xff09;方法进行&#xff0c;这个方法是用来在节点创建渲染完成后进行的操作 that.$nextTick(() > {let qrcode …