C++学习一STL

news2025/3/11 3:09:16

文章目录

  • 一、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 头文件 <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>= p1
	p – 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 == val

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

unique
	template<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) 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<class RanIt> 
     void sort(RanIt first, RanIt last); 
     按升序排序。判断x是否应比y靠前,就看 x < y 是否为true
     
     template<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 < y

	template<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小于y

lower_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_bound
	template<class FwdIt, class T>
	FwdIt upper_bound(FwdIt first, FwdIt last, const T& val); 
要求[first,last)是有序的,
查找[first,last)中的,最小的位置 FwdIt,使得[FwdIt,last) 中所有的元素都比 val 大

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

merge
	template<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 开头。

includes
	template<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_difference
	template<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_intersection
	template<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_difference
	template<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_union
	template<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的内容放入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 <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; //输出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 <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并清空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<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) 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<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;   //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 <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.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 <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小于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,则没有问题

总结

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用神卓互联内网穿透搭建远程访问公司ERP系统

神卓互联是一款企业级内网穿透软件&#xff0c;可以将内网中的服务映射到公网上&#xff0c;实现内网服务的访问。通过神卓互联&#xff0c;您可以远程访问ERP系统。在使用神卓互联进行内网穿透时&#xff0c;您只需要在生成的公网地址后面加上ERP系统的端口号&#xff0c;即可…

未来公文的智能化进程

随着技术的飞速发展&#xff0c;公文——这个有着悠久历史的官方沟通方式&#xff0c;也正逐步走向智能化的未来。自动化、人工智能、区块链...这些现代科技正重塑我们的公文制度&#xff0c;让其变得更加高效、安全和智慧。 1.语义理解与自动生成 通过深度学习和NLP&#xff…

爬虫代理一分钟请求数量升级

Hello&#xff0c;各位爬中高手&#xff01;你是否曾经遇到过爬虫代理一分钟请求数量过少的问题&#xff1f;别急&#xff0c;今天我来分享一些方法&#xff0c;让你的爬虫代理请求数量快速飙升&#xff01;这些技巧简单易行&#xff0c;让你的爬虫工作更加高效。 在进行爬虫工…

TikTok连续12个季度跻身全球下载量排行第一

据报道&#xff0c;美国数据公司SensorTower发布了《2023年第二季度全球移动应用下载报告》&#xff0c;数据统计了全球范围内以及各地区下载量最高的App&#xff0c;以及购物类App下载量最高的市场。数据显示&#xff0c;TikTok再次荣登全球下载量最高的应用程序榜首&#xff…

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

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

【算法测试】盒子上绑定好的算法,只能输入rtsp流, 如何测试其精度? 讲图片拼接成视频,然后生成rtsp流

文章目录 前言1. 安装rtsp服务器2. 用ffmpeg推送视频到rtsp3.用VLC 承接播放&#xff0c;查看效果&#xff1a;4. 找一个测试集图片集&#xff0c;生成视频 前言 要测试盒子上的算法精度&#xff0c;但盒子的算法只能输入rtsp流&#xff0c;这样我们难道只能去摄像头底下演示效…

【多线程】JUC的常见类

1. Callable 接口 首先先来认识下什么是 JUC&#xff0c;JUC 全称为 java.util.concurrent&#xff0c;这个包里面放了并发编程(多线程相关的组件) Callable 接口类似于 Runnable 一样&#xff0c;Runnable 用来描述一个任务&#xff0c;而 Callable 也是用来描述一个任务的。 …

爱分析发布2023商业智能最佳实践案例,OceanMind海睿思再次入选!

近日&#xff0c;中国领先的产业数字化研究与咨询机构 爱分析&#xff0c;在北京举办了第五届数据智能高峰论坛&#xff0c;活动以“激活数据资产&#xff0c;释放数据价值”为主题。 中新赛克海睿思作为数字化转型优秀厂商代表受邀参会。 会上&#xff0c;爱分析重磅发布了《…

Keepalived + Nginx 实现高可用

一、简介 浮动IP、漂移IP地址又叫做VIP&#xff0c;也就是虚拟IP。 Keepalived 是一种高性能的服务器高可用或热备解决方案。 Keepalived 可以用来防止服务器单点故障的发生&#xff0c;通过配合 Nginx 可以实现 web 前端服务的高可用。 Keepalived 以 VRRP 协议为实现基础&a…

批量删除文件名前的数字编号?

批量删除文件名前的数字编号&#xff1f;如果你在网上经常下载文件&#xff0c;你会发现下载的文件名称前面一般都会有很的数字编号&#xff0c;这些数字编号有时候会非常的长&#xff0c;导致文件的名称也非常的长&#xff0c;这样对于文件的管理和查找使用是不利的。所以为了…

推荐一个绘图平台(可替代Visio)

不废话&#xff0c;简易记网址&#xff1a; draw.io 网站会重定向到&#xff1a;https://app.diagrams.net/

LeetCode 141.环形链表

文章目录 &#x1f4a1;题目分析&#x1f4a1;解题思路&#x1f514;接口源码&#x1f4a1;深度思考❓思考1❓思考2 题目链接&#x1f449; LeetCode 141.环形链表&#x1f448; &#x1f4a1;题目分析 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中…

XDocReport文书生成总结

最近弄一个业务需要搞很多的word文档导出&#xff0c;供前端下载。之前的实现方式一般是先把word转成XML格式&#xff0c;然后赋值变量&#xff0c;这种方式虽然可行&#xff0c;但是遇到那种长篇且变量又多的文档&#xff0c;就很让人头大&#xff0c;密密麻麻的一堆代码&…

Spring-3-Spring AOP概念全面解析

今日目标 能够理解AOP的作用 能够完成AOP的入门案例 能够理解AOP的工作流程 能够说出AOP的五种通知类型 一、AOP 1 AOP简介 思考&#xff1a;什么是AOP,AOP的作用是什么&#xff1f; 1.1 AOP简介和作用【理解】 AOP(Aspect Oriented Programming)面向切面编程&#xff0c;一…

Windows系统修改域名DNS指向两种方式

一、直接打开对应文件进行修改 1、进入hosts文件目录&#xff1a;C:\Windows\System32\drivers\etc 2、右键打开HOSTS文件进行编辑&#xff0c;将需要对应的域名和IP地址进行配置 编写完成后 Ctrl s 进行保存即可。 二、使用DOS命令进行修改 1、按住键盘win键 r 打开命令…

设计师必备的5个PNG免抠素材网站,简直不要太好用~

广大设计师们是不是经常要用免抠素材的时候网上找的质量差&#xff0c;还要各种付费才能使用&#xff0c;最后只能打开PS慢慢的扣&#xff0c;真的很费时间。本期我就给大家推荐5个高质量、免费的免抠素材网站&#xff0c;有需要的朋友们赶紧收藏。 菜鸟图库 https://www.suc…

2021年3月全国计算机等级考试真题(C语言二级)

2021年3月全国计算机等级考试真题&#xff08;C语言二级&#xff09; 第1题 算法空间复杂度的度量方法是&#xff08;&#xff09; A. 算法程序的长度 B. 算法所处理的数据量 C. 执行算法所需要的工作单元 D. 执行算法所需要的存储空间 正确答案&#xff1a;D 第2题 下列叙…

wangEditor修改节点数据

前言 wangEditor简介 wangEditor 是一款基于 JavaScript 和 jQuery 的开源富文本编辑器&#xff0c;具有简单易用、功能丰富的特点。它提供了一整套的富文本编辑功能&#xff0c;包括文字样式设置、插入图片、插入表格、插入链接、代码块等。wangEditor 支持多种浏览器&#x…

大数据时代下的数据中心运维管理

摘要&#xff1a;本文将从数据中心运维管理的角度&#xff0c;联系现实情况&#xff0c;对运维管理进行研究&#xff0c;期望通过本项目的研究&#xff0c;显著提升数据中心运维治理的整体质量。这样&#xff0c;才能充分发挥大数据的价值&#xff0c;并推动企业加速发展。 关…

将nginx内存池代码单独编译运行,了解nginx内存池工作原理,附代码

初识nginx——内存池篇 https://www.cnblogs.com/magicsoar/p/6040238.html 为了自身使用的方便&#xff0c;Nginx封装了很多有用的数据结构&#xff0c;比如ngx_str_t ,ngx_array_t, ngx_pool_t 等等&#xff0c;对于内存池&#xff0c;nginx设计的十分精炼&#xff0c;值得我…