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

2.顺序容器

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

  1. vector 头文件
    动态数组。元素在内存连续存放。随机存取任何元素都能在常数时间完成。在尾端增删元素具有较佳的性能(大部分情况下是常数时间)。
    C++学习一STL_第1张图片

  2. deque 头文件
    双向队列。元素在内存连续存放。随机存取任何元素都能在常数时间完成(但次于vector)。在两端增删元素具有较佳的性能(大部分情况下是常数时间)。
    C++学习一STL_第2张图片
    C++学习一STL_第3张图片

  3. list 头文件
    双向链表。元素在内存不连续存放。在任何位置增删元素都能在常数时间完成。不支持随机存取。
    C++学习一STL_第4张图片

3.关联容器

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

4.容器适配器

  1. queue 头文件
    队列。插入只可以在尾部进行,删除、检索和修改只允许从头部进行。先进先出。
    C++学习一STL_第6张图片
  2. priority_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 
#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>= p1
	p – p1 : p1和p之间的元素个数

4.容器上的迭代器类别

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

四、算法

1.概念

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

  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 
Fun for_each(InIt first, InIt last, Fun f);
对[first,last)中的每个元素 e ,执行 f(e) , 要求 f(e)不能改变e。

count:
template 
size_t count(InIt first, InIt last, const T& val);
计算[first,last) 中等于val的元素个数

count_if 
template 
size_t count_if(InIt first, InIt last, Pred pr);
计算[first,last) 中符合pr(e) == true 的元素 e的个数

min_element:
template 
FwdIt min_element(FwdIt first, FwdIt last); 
返回[first,last) 中最小元素的迭代器,以 “< ”作比较器。最小指没有元素比它小,而不是它比别的不同元素都小因为即便a!= b, a 
FwdIt max_element(FwdIt first, FwdIt last); 
返回[first,last) 中最大元素(它不小于任何其他元素,但不见得其他不同元素都小于它)的迭代器,以 “< ”作比较器。

find
template 
InIt find(InIt first, InIt last, const T& val);
返回区间 [first,last) 中的迭代器 i ,使得 * i == val

find_if
template 
InIt find_if(InIt first, InIt last, Pred pr);
返回区间 [first,last) 中的迭代器 i, 使得 pr(*i) == true
#include 
#include 
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 
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 
#include 
#include 
#include 
#include 
#include 

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
	拷贝区间到另一个区间。连续相等的元素,只拷贝第一个到目标区间 (可自定义比较器)

unique
	template 
	FwdIt unique(FwdIt first, FwdIt last); 
	用 == 比较是否等

	template 
	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) 3
    vector<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) 6
    return 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 
     void sort(RanIt first, RanIt last); 
     按升序排序。判断x是否应比y靠前,就看 x < y 是否为true
     
     template
     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 
     void make_heap(RanIt first, RanIt last); 
     将区间 [first,last) 做成一个堆。用 < 作比较器
     
     template 
     void make_heap(RanIt first, RanIt last, Pred pr);
     将区间 [first,last) 做成一个堆。用 pr 作比较器
    
  3. push_heap 函数模板

     template
     void push_heap(RanIt first, RanIt last); 
     
     template 
     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 
     void pop_heap(RanIt first, RanIt last); 
     
     template 
     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
	bool binary_search(FwdIt first, FwdIt last, const T& val); 
	上面这个版本,比较两个元素x,y 大小时, 看 x < y

	template 
	bool binary_search(FwdIt first, FwdIt last, const T& val, Pred pr);
	上面这个版本,比较两个元素x,y 大小时, 若 pr(x,y) 为true,则认为x小于y

lower_bound:
	template 
	FwdIt lower_bound(FwdIt first, FwdIt last, const T& val); 
要求[first,last)是有序的,
查找[first,last)中的,最大的位置 FwdIt,使得[first,FwdIt) 中所有的元素都比 val 小

upper_bound
	template
	FwdIt upper_bound(FwdIt first, FwdIt last, const T& val); 
要求[first,last)是有序的,
查找[first,last)中的,最小的位置 FwdIt,使得[FwdIt,last) 中所有的元素都比 val 大

equal_range
	template 
	pair 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的结果

merge
	template 
	OutIt merge(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt x);用 < 作比较器
	
	template 
	OutIt merge(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt x, Pred pr);用 pr 作比较器
把[first1,last1), [ first2,last2) 两个升序序列合并,形成第3 个升序序列,第3个升序序列以 x 开头。

includes
	template 
	bool includes(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2);
	
	template 
	bool includes(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, Pred pr);
判断 [first2,last2)中的每个元素,是否都在[first1,last1)中第一个用 <作比较器,第二个用 pr 作比较器, pr(x,y) == true说明 x,y相等。

set_difference
	template 
	OutIt set_difference(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt x); 
	
	template 
	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_intersection
	template 
	OutIt set_intersection(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt x); 
	
	template 
	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_difference
	template 
	OutIt set_symmetric_difference(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt x); 
	
	template 
	OutIt set_symmetric_difference(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt x, Pred pr);
把两个区间里相互不在另一区间里的元素放入x开始的地方。

set_union
	template
	OutIt set_union(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt x); 用<比较大小
	
	template 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
class bitset 
{
….. 
};
实际使用的时候,N是个整型常数
如:
bitset<40> bst;
bst是一个由40位组成的对象,用bitset的函数可以方便地访问任
何一位。

bitset的成员函数:

bitset& operator&=(const bitset& rhs); 
bitset& operator|=(const bitset& rhs); 
bitset& operator^=(const bitset& rhs); 
bitset& operator<<=(size_t num); 
bitset& operator>>=(size_t num); 
bitset& set(); //全部设成1
bitset& set(size_t pos, bool val = true); //设置某位
bitset& reset(); //全部设成0
bitset& reset(size_t pos); //某位设成0
bitset& flip(); //全部翻转
bitset& 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& rhs) const; 
bool operator!=(const bitset& rhs) const;
bool test(size_t pos) const; //测试某位是否为 1
bool any() const; //是否有某位为1 
bool none() const; //是否全部为0
bitset operator<<(size_t pos) const; 
bitset operator>>(size_t pos) const; 
bitset 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 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的内容放入v
    cout << "1) " << v.end() - v.begin() << endl;
    //两个随机迭代器可以相减,输出 1) 5
    cout << "2) "; PrintVector(v.begin(),v.end());
    //2) 1 2 3 4 5
    v.insert(v.begin() + 2, 13); //在begin()+2位置插入 13
    cout << "3) "; PrintVector(v.begin(),v.end());
    //3) 1 2 13 3 4 5
    v.erase(v.begin() + 2); //删除位于 begin() + 2的元素
    cout << "4) "; PrintVector(v.begin(),v.end());
    //4) 1 2 3 4 5
    vector<int> v2(4,100); //v2 有4个元素,都是100
    v2.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 100
    v.erase(v.begin() + 1, v.begin() + 3);
    //删除 v 上的一个区间,即 2,3
    cout << "6) "; PrintVector(v.begin(),v.end());
    //6) 1 4 5
    return 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 
#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; //输出3
    p = 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 
#include 
#include 
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::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并清空lst2
    cout << "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 equal_range(const T & val);
     同时求得lower_bound和upper_bound。
     
     iterator erase(iterator it);
     删除it指向的元素,返回其后面的元素的迭代器(Visual studio 2010上如此,但是在
     C++标准和Dev C++中,返回值不是这样)。
    
#include  //使用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) 2
    cout << "2) ";
    Print(m1.begin(), m1.end()); //输出 2) 4 8 19 22 22 33 40
    //m1元素:4 8 19 22 22 33 40
    MSET1::iterator pp = m1.find(19);
    if (pp != m1.end()) //条件为真说明找到
        cout << "found" << endl;
    //本行会被执行,输出 found
    cout << "3) ";
    cout << *m1.lower_bound(22) << ","
         << *m1.upper_bound(22) << endl;
//输出 3) 22,33
    pp = m1.erase(m1.lower_bound(22), m1.upper_bound(22));
//pp指向被删元素的下一个元素
    cout << "4) ";
    Print(m1.begin(), m1.end()); //输出 4) 4 8 19 33 40
    cout << "5) ";
    cout << *pp << endl; //输出 5) 33
    MSET2 m2; // m2里的元素按n的个位数从小到大排
    m2.insert(a, a + SIZE);
    cout << "6) ";
    Print(m2.begin(), m2.end()); //输出 6) 40 22 33 4 8 19
    return 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 6
    pair< IT,bool> result;
    result = st.insert(5); // st变成 1 2 3 4 5 6
    if( result.second ) //插入成功则输出被插入元素
        cout << * result.first << " inserted" << endl; //输出: 5 inserted
    if( st.insert(5).second )
        cout << * result.first << endl;
    else
        cout << * result.first << " already exists" << endl; //输出 5 already exists
    pair<IT,IT> bounds = st.equal_range(4);
    cout << * bounds.first << "," << * bounds.second ; //输出:4,5
    return 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成员变量,其类型是Key
	multimap 中允许多个元素的关键字相同。元素按照first成员变量从小到大
	排列,缺省情况下用 less 定义关键字的“小于”关系。

示例:

#include 
#include 
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 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,即“<” 定义“小
	于”。

map的[ ]成员函数

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

示例:

#include 
#include 
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;   //0
    pairs.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.28
    for (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 
#include 
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.2
    cout << 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.8
    return 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 
#include 
#include 
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 
#include 
#include 
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()是个对象
    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小于y
	2) op(x,y)返回值为true
	3) 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,则没有问题

总结

你可能感兴趣的:(c++,学习,java)