C++标准模板库STL

标准模板库(standard template library,STL)是C++十分强大的库,其提供了一组表示容器、蝶代替、函数对象和算法的模板。STL实际上是使用泛型编程(generic programming)编写的,其建立在一些概念的抽象之上,如容器、迭代器、分配器等。OOP和泛型编程的理念不同,OOP关注编程的数据表示,泛型编程关注的则是算法,拥有更高的抽象水平。

以下介绍STL中的泛型编程的理念、容器类、迭代器、算法以及函数对象。

目录

泛型编程

迭代器

函数对象

容器类

序列

关联容器

无序关联容器

算法


泛型编程

为了能够让泛型编程能够适用于许多类型,泛型编程主要通过类模板和函数模板以及各种抽象概念实现。抽象概念包括分配器、迭代器、容器等。这些抽象概念有对应具体的类,如allocator类、iteration类等。

  1. STL的几个术语——概念、改进与模型

    概念(concept)指的是描述的要求,如对迭代器的基本要求。改进(refinement)指的是概念的继承,如正向迭代器对于输入迭代器、输出迭代器是改进。模型(model)指的是具体实现,例如C++中的iterator类是迭代器的模型。
     
  2. 分配器Allocator

    分配器Allocator是管理内存的对象。
     
  3. 迭代器Iterator

    迭代器是能够用来遍历容器的对象,其使得算法可以独立于容器类、具体类型。

    迭代器Iterator实际上是满足以下基本概念(concept,STL术语,指一系列要求)的“对象”:
    ①能解除引用以访问引用值,即定义了解除引用运算符*
    ②能够实现迭代器之间的复制,即定义了赋值运算符=
    ③能够实现迭代器之间的比较,即定义了==与!=运算符
    ④能够遍历容器中的每个对象,即定义了++运算符

    从上述要求来看,其实指针和类都可以作为迭代器的具体实现,实际上迭代器就是广义指针。
     
  4. 容器Container

    容器Container则是可以按照一定结构储存数值的对象,比如数组、链表等。在STL中,容器都是同质的,只能放相同类型的值。
     
  5. 函数对象

    函数对象是类似于函数的对象,也叫函数符(functor),其指的是可以以函数方式与()结合使用的任意对象。函数名、函数指针、重载了()运算符的类都是函数对象。

迭代器

迭代器是一种概念的抽象,也有具体的实现(即iterator类)。不同算法对迭代器的要求不同,根据不同要求(读写数据、遍历方向、随机访问),其分为5类。每种迭代器均能够满足前文提及的概念,但也具有各自不同的概念。

实际上,这5类迭代器具有一定继承关系:正向迭代器继承了输入迭代器、输出迭代器的所有特点;双向迭代器继承了正向迭代器的所有特点;随机迭代器继承了双向迭代器的所有特点

  1. 输入迭代器InputIterator

    输入迭代器指的是能从容器中读取信息(但不一定可以修改)的迭代器。其允许读取,但不允许修改。输入迭代器是单向迭代器,只能前进,不能倒退,并且不保证第二遍遍历顺序不变,也不能保证先前值可以被解除引用(是说不能保存先前值后再解除引用?)。

    使用输入迭代器的算法必须是单通行(single pass)的,不依赖于前一次遍历时的迭代器值,也不依赖于本次遍历中前面迭代器值(?)
     
  2. 输出迭代器OutputIterator

    输出迭代器指能从程序中读取并储存信息到容器的迭代器。其允许解除引用以修改容器值,但不允许读取
     
  3. 正向迭代器Forward Iterator

    正向迭代器只使用++遍历但其每次的遍历顺序相同,并且可以对先前值解除引用(若保存先前值的话),同时可读可写数据(声明const常量即成为只读迭代器)

    使用正向迭代器的算法可以是多通行的。
     
  4. 双向迭代器

    双向迭代器具有正向迭代器所有特点,但允许前进和倒退,因为它定义了++和--两类运算符。
     
  5. 随机访问迭代器
    随机访问迭代器具有双向迭代器的所有特点,但允许随机访问(即访问容器中任意元素)。
     
  6. C++中一些预定义的迭代器
    C++提供了具体的迭代器模型,如ostream_iterator、istream_iterator、reverse_iterator、back_insert_iterator、front_insert_iterator等。它们都包含在头文件iterator中。

    · ostream_iterator
    ostream_iterator是输出迭代器的模型。其声明的代码如下:
    /*声明:
    ostream_iterator<被发送给输出流的类型,输出流的类型> 迭代器对象名(输出流);//构造函数1
    ostream_iterator<被发送给输出流的类型,输出流的类型> 迭代器对象名(输出流,数据项的分隔符);//构造函数2
    */
    
    //示例
    ostream_iterator<int,char> objOI(cout);

    · istream_iterator
    istream_iterator是输入迭代器的模型。其构造函数和ostream_iterator相近:
    /*声明:
    istream_iterator<输入流读取的类型,输入流的类型> 迭代器对象名(输入流);//构造函数1
    istream_iterator<输入流读取的类型,输入流的类型> 迭代器对象名(输入流,数据项的分隔符);//构造函数2
    */
    
    //示例
    istream_iterator<int,char> objII(cin);

    · reverse_iterator反向迭代器

    reverse_iterator是为了简化函数使用而创建的,其指向序列的末端,对其递增实际上使其递减,其指向原对象之前的对象。常用于反序问题。

    · back_insert_iterator、front_insert_iterator、insert_iterator

    这三种迭代器均是为了插入算法服务的,都是输出迭代器的模型,但适用于不同的容器类,因此在声明对象时,都需要声明相应的容器类型。

    #back_insert_iterator将元素插入到末尾只能用于允许在尾部插入的容器(如队列queue)
    #front_insert_iterator将元素插入到前端只能用于允许在头部插入的容器(如栈stack、双向队列dequeue)
    #insert_iterator则将元素插入到指定位置前,该指定位置通过insert_iterator的构造函数传入

    三种迭代器的构造函数如下:
    /*构造函数
    back_insert_iterator<容器类型> 迭代器名(类型对应的容器对象);
    front_insert_iterator<容器类型> 迭代器名(类型对应的容器对象);
    insert_iterator<容器类型> 迭代器名(类型对应的容器对象,插入位置);
    //插入位置实际上也是个迭代器
    */
    
    //示例
    
    #include<iterator>
    #include<iostream>
    #include<vector>
    using namespace std;
    vector<int> v(4);
    back_insert_iterator<vector<int>> objBII(v);
    insert_iterator<vector<int>> objII(v,v.begin());
    
    

函数对象

  1. 定义与种类

    函数对象也称为函数符(functor),指的是能够与运算符()结合发挥与函数类似作用的任意对象。函数对象包括函数名、函数指针以及重载了()运算符的类对象
     
  2. 函数符的改进——生成器、一元函数、二元函数、一元谓词、二元谓词

    函数符按照调用参数、返回类型的不同,分为几种类型:
    生成器(generator):不用参数即可调用的函数符。例如默认构造函数就是一种生成器。
    一元函数(unary function):需要使用一个参数即可调用的函数符
    二元函数(binary function):需要使用两个参数即可调用的函数符
    谓词(predicate)返回bool的一元函数称为谓词。
    二元谓词binary predicate):返回bool的二元函数称为二元谓词。
  3. 一些预定义的函数符

    C++在头文件functional中定义了多个模板类函数对象,常用的主要有less<>、greater<>、plus<>等,以下作部分介绍:

    · 预定义的函数符​​​​​
    预定义的函数符和许多运算符相对应:
    运算符函数符
    +plus
    -minus
    *multiplies
    /divides
    %modulus
    -(取负)negate
    ==equal_to
    !=not_equal_to
    >greater
    <less
    >=greater_equal
    <=less_equal
    &&logical_and
    ||logical_or
    !logical_not

    · 预定义函数符的使用
    这些函数符均是用模板写的,因此调用于生成函数符对象时,需要在尖括号内声明相应的类型
     
    /*
    //调用于生成函数符对象:
    函数符名<类型> 对象名;
    
    //调用函数
    对象名(左值,右值)
    
    //传入容器的构造函数作为比较对象时
    //只需传入函数符即可,不需要加上()
    */
    
    //示例
    void main()
    {
    	plus<int> add;
    	int ans=add(1,2);
    	cout<<ans<<endl;
    }
    
    -----输出-----
    3
  4. 函数符的使用

    · 通过类定义一个函数符

    如前文所说,重载了()运算符的类也可以作为函数符使用,作为比较对象传入容器构造函数时,只需传入类名即可。

    示例代码如下:
    class Greater//类函数符
    {
    public:
    	Greater(const int & val_a,const int & val_b):a(val_a),b(val_b){};
    	~Greater();
    	bool operator()(){return a>b;}//重载()运算符
    
    private:
    	int a;
    	int b;
    };
    
    void main()
    {
    	set<int,Greater> objSet;//传入Greater作为比较对象
    }
    上文的代码段中的Greater是针对int类型的,其实也可以像预定义的函数符一样,将其定义为一个类模板,这样其普适性会更强。
     

容器类

容器是按照一定组织结构储存数值的对象,其实就是一系列数据结构的实现(或者用STL的术语来说,模型)。STL中有许多强大的容器类,主要有几大类:

  1. 序列(如单向链表forward_list、双向链表list、队列queue、矢量vector、双向队列dequeue、优先队列/堆priority_queue)
  2. 关联容器(如地图/键值对map、集合set、多重映射multimap)
  3. 无序关联容器(如哈希表unordered_map、unordered_set、unordered_multimap等)。

容器类的基本特征(或者说基本成员)主要有:(X表示序列类型,t为类型T的值,a、b为容器对象,n表示整数,p、q、i、t为迭代器)

表达式返回类型说明时间复杂度
X::iterator-满足正向迭代器的任何迭代器编译时间
X::value_typeTT的类型编译时间
X u创建一个空容器对象u固定时间
X()创建一个匿名空容器对象固定时间
X u(a)迭代器调用复制构造函数,使用容器对象a创建容器对象u线性时间
X u=avoid同X u(a)线性时间
a.begin()(常量)迭代器返回指向容器第一个元素的迭代器固定时间
a.end()迭代器返回指向容器超尾(即最后一个元素以后)的迭代器固定时间
a.size()整数返回容器元素数固定时间
a.swap(b)void交换a和b的内容固定时间
a==bbool如果a、b长度相同,且a、b中的每个元素都相同,则返回真线性时间
a!=bbool返回!(a==b)线性时间

编译时间指操作将在编译时执行,执行时间为0;固定时间、线性时间均表示操作在运行时执行,固定时间但独立于对象的元素数,线性时间则与元素数成正比。

以下主要从容器类的特点、声明、方法。介绍各容器类,可以联系数据结构的内容以加深理解。使用各容器前,记得包含它们各自的头文件,头文件名一般与它们的名称相同。
 

序列

序列是对容器概念的改进,在容器的概念之上,要求:
①迭代器至少应为正向迭代器
②元素应按严格的线性顺序排列


下表总结了每种序列的基本成员的相同部分:(X表示序列类型,t为类型T的值,a为序列对象,n表示整数,p、q、i、t为迭代器)

成员表达式返回类型说明
X a(n,t)-声明一个由n个t组成的序列对象a
X(n,t)声明一个由n个t组成的匿名序列
X a(i,t)声明一个由区间[i,j)之间的内容组成的序列对象a
X(i,t)声明一个由区间[i,j)之间的内容组成的匿名序列
a.insert(p,t)迭代器将t插入到p前面
a.insert(p,n,t)void将n个t插入到p前面
a.insert(p,i,j)void将区间[i,j)的内容插入到p前面
a.erase(p)迭代器删除p
a.erase(p,q)迭代器删除区间[p,q)的内容
a.clear()void清空所有内容

 以下作各序列的简介。各类的方法可以查看相关STL使用目录(例如C++ primer plus第六版的附录G)。

  1. 单向链表forward_list

    单向链表中,每个节点只能链接到下一个节点,即只能前进遍历下一个节点。forward_list使用的是正向迭代器,是不可反转的容器。

    其基本操作与list类似,功能较少但更紧凑。
     
  2. 双向链表list

    双向链表中,除了第一个和最后一个元素外,每个元素都与前后两个节点相链接,即保存有前后两个节点的访问信息。list使用的是双向迭代器,允许双向遍历。list是可反转容器,但不允许随机访问与数组表示法。

    list在删除、插入的操作开销是固定时间,遍历则是线性时间。

    list提供的成员函数如下:(T为元素类型;Alloc为分配器,一般有默认值;N为元素数)
    函数说明时间复杂度
    void merge(list<T,Alloc>&x)将对象与相同类型的链表x合并线性时间
    void remove(const T & val)删除val的所有实例线性时间
    void sort()使用<运算符排序NlogN
    void splice(iterator pos, list<T,Alloc> x)将相同类型链表x插入到p位置前,并且x将被置空固定时间
    void unique()连续相同元素压缩为单个元素线性时间
  3. 矢量vector

    矢量vector是动态数组。它提供了元素的随机访问,需要使用随机访问迭代器。

    在尾部删除或插入的时间是固定时间,在头部、序列中间删除或者插入是线性时间。

    vector是可反转容器,含有rend()、rbegin()两个方法:
    函数返回类型说明
    void rend()reverse_iterator返回指向反转序列的末尾元素(即正序第一个元素)的迭代器
    void rbegin()reverse_iterator返回指向反转序列第一个元素(即正序最后一个元素)的迭代器
  4. 队列queue

    队列queue只允许在头部删除,尾部插入,不允许随机访问/遍历。

    STL中的queue实际上是一个适配器,其让底层类(即实现的基础,STL中默认为deque,实际上也可以用链表、数组实现queue转换成了队列。

    其基本操作如下:
    函数说明
    bool empty() const查看队列是否为空
    int size() const查看队列元素个数
    T & front()返回头部元素的引用
    T & back()返回尾部元素的引用
    void push(T &x)将元素x压入队尾
    void pop()删除头部元素
  5. 双向队列dequeue(doubled-ended queue)

    双向队列dequeue允许在头部和尾部插入或者删除。其也提供了随机访问的功能,因此需要使用随机访问迭代器。

    其在头部、尾部插入或者删除的时间为固定时间,在序列中间插入或者删除的时间为线性时间。
     
  6. 优先队列/堆priority_queue

    优先队列/堆priority_queue将最大的元素放在队首,在STL中堆的底层类是vector。

    堆支持的操作与queue一样:front()、back()、push()、pop()。堆获取队首元素所需时间是固定时间。声明堆对象时,可以修改用于确定哪个元素放到队首的比较方式:
    /*
    priority_queue<元素类型> 堆对象名;//构造函数1
    priority_queue<元素类型> 堆对象名(greater<元素类型>)//构造函数2
    */
    greater<>是预定义的函数对象。
     
  7. 栈stack

    栈只允许从栈顶插入、删除、访问元素,不允许随机访问、遍历。

    stack允许的操作如下:
    函数说明
    bool empty() const查看队列是否为空,若为空返回true,非空则返回false
    int size() const查看栈元素个数
    T & top()返回栈顶元素的引用
    void push(const T &x)将元素x压入栈顶
    void pop()删除栈顶元素
  8. 静态数组array

    array实际上并不是STL容器,因为其长度是固定的,但是可以将许多STL算法用于array对象,例如copy()、for_each()。

    其允许随机访问、遍历。
     

关联容器

关联容器是对容器概念的改进,其将值与键关联在一起,并使用键查找值。关联容器都提供了对元素的快速访问(其所需时间为固定时间)。关联容器一般通过树实现。

  1. 集合set、multiset

    set、multiset都位于头文件set中。

    set中的键是唯一的,不能存储多个相同值,储存的键就是储存的值,故键值类型是一样的
    。set可以反转,也可以排序。

    multiset中可以储存多个重复值,键值仍然相同,并且是按照一定顺序排列的。其是用红黑树实现的。

    · set和multiset共有的成员
    函数说明
    X::key_type键Key,键类型
    X::key_compare键的比较对象Compare,默认为less<key_type>
    X::value_compare值的比较对象Compare,二元谓词类型

    · set的成员函数
    set的成员函数主要与数学意义上的集合操作相同,具体如下:(i、j为set对象A的区间的迭代器, p、q为对象B的区间的迭代器,objOI是输出迭代器,t为类型T对象,c为用于比较的函数对象,迭代器类型为set<T>::iterator
    函数说明
    set<T> A()创建键值类型为T的set对象A
    set<T> A(B.begin(), B.end(), c)创建键值类型为T的set对象A,其内容为对象B的区间[begin, end)的内容,并使用函数对象c作为比较对象,c默认为less<T>
    set_union(i, j, p, q, objOI)并集,将对象A区间[i,j)、对象B区间[p,q)的内容合并并输出到objOI中。objOI需要是输出迭代器,不能是某个容器对象的begin(),因为begin()返回的是常量迭代器,此时可以用insert_iterator。
    set_difference(i, j, p, q, objOI)差集,找出对象A区间[i,j)、对象B区间[p,q)相差的内容,并输出到objOI中。
    set_intersection(i, j, p, q, objOI)交集,找出对象A区间[i,j)、对象B区间[p,q)的相交内容,并输出到objOI中。
    A.find(k)返回一个迭代器,该迭代器指向键与 k 相同的元素;如果没有找到这样的元素,则返回 a.end()
    A.lower_bound(k)返回一个迭代器,该迭代器指向第一个键不小于 k 的元素
    A.upper_bound(k)返回一个迭代器,该迭代器指向第一个键不大于 k 的元素
    A.insert(t)插入一个值为t的键
    A.insert(p, q)插入B集合中区间[p,q)的值

    · multiset成员方法
    multiset成员方法如下:
    (i、j为multiset对象A的区间的迭代器, p、q为对象B的区间的迭代器,objOI是输出迭代器,t为类型T对象,c为用于比较的函数对象,迭代器类型为multiset<T>::iterator
     
    函数说明
    multiset<T, c=less<T>, Alloc=allocator<T>> A()创建键值类型为T的set对象A,比较对象c默认为less<T>函数对象,分配器Alloc默认为allocator<T>
    multiset<T> A(B.begin(), B.end(), c)创建键值类型为T的set对象A,其内容为对象B的区间[begin, end)的内容,并使用函数对象c作为比较对象,c默认为less<T>
    A.find(k)返回一个迭代器,该迭代器指向键与 k 相同的元素;如果没有找到这样的元素,则返回 a.end()
    A.lower_bound(k)返回一个迭代器,该迭代器指向第一个键不小于 k 的元素
    A.upper_bound(k)返回一个迭代器,该迭代器指向第一个键不大于 k 的元素
    A.insert(t)插入一个值为t的键
    A.insert(p, q)插入B集合中区间[p,q)的值

    · set、multiset的使用
    #include<iostream>
    #include<set>
    using namespace std;
    
    int main()
    {
    	int arrInt[]={12,2,3,5,6};
    	int array[] = { 0, 2, 1, 4, 3, 6, 5, 7, 8, 9, 0, 7, 6};
    	set<int> objSET(&arrInt[0],&arrInt[4]);
    	cout<<*objSET.find(2)<<endl;//对返回的迭代器解引用即可获得值
    	multiset<int> ms(array, array + sizeof(array) / sizeof(array[0]));
    	cout <<*ms.find(6)<<endl;
    	
    	cin.get();
    	return 0;
    }
    
    -----输出-----
    2
    6

  2. 映射map、多重映射multimap

     

    map、multimap都位于头文件map中。它们都是按照键排序的,也可以反转。

    map中的键是唯一的,不能存储多个相同值,键、值互相关联,且类型可以不同
    multimap中可以储存多个重复键,键、值互相关联,且类型可以不同。

    · map和multimap共有的成员

    函数说明
    X::key_type表示键Key,类型
    X::key_compare表示键的比较对象Compare,默认为less<key_type>
    X::value_compare二元谓词类型,与 set 和 multiset 的 key_compare 相同,为 map 或 multimap 容器中的 pair<const Key, T> 值提供了排序功能
    X::mapped_compare表示值类型,即T

    · map的成员函数
    set的成员函数主要与数学意义上的集合操作相同,具体如下:(i、j为set对象A的区间的迭代器, p、q为对象B的区间的迭代器,objOI是输出迭代器,t为类型T对象,c为用于比较的函数对象,迭代器类型为map<T>::iterator
    函数说明
    map<KT,VT, c=less<KT>,Alloc=allocator<pair<KT, VT>>> A()创建键类型为KT、值类型为VT的set对象A,比较对象c默认值为less<KT>,分配器Alloc默认为allocator<pair<KT, VT>>
    map<KT,VT> A(p, q, c)创建键值类型为T的set对象A,其内容为对象B的区间[p, q)的内容,并使用函数对象c作为比较对象,c默认为less<T>
    A.find(k)返回一个迭代器,该迭代器指向键与 k 相同的元素;如果没有找到这样的元素,则返回 a.end()。

    map<KT,VT>::iterator迭代器实际上指向pair<KT,VT>对象,通过first成员访问键,second成员访问值。
    A[k]返回一个指向与键 k 关联的值的引用(map特有的数组表示法)
    A.lower_bound(k)返回一个map<KT,VT>::iterator类型的迭代器,该迭代器指向第一个键不小于 k 的元素
    A.upper_bound(k)返回一个迭代器,该迭代器指向第一个键不大于 k 的元素
    A.insert(pair<KT,VT>(v,k))插入一个键值对为(v,k)的pair对象
    A.insert(p, q)插入B集合中区间[p,q)的值

    · multimap成员方法
    multimap成员方法如下:
    (i、j为multimap对象A的区间的迭代器, p、q为对象B的区间的迭代器,objOI是输出迭代器,t为类型T对象,c为用于比较的函数对象,迭代器类型为multimap<T>::iterator
    函数说明
    multimap<KT,VT,c=less<KT>,
    Alloc=allocator<pair<KT, VT>>> A()
    创建键类型为KT、值类型为VT的multimap对象A,比较对象c默认为less<T>函数对象,分配器Alloc默认为allocator<T>
    multimap<KT,VT>A(B.begin(), B.end(), c)创建键值类型为T的set对象A,其内容为对象B的区间[begin, end)的内容,并使用函数对象c作为比较对象,c默认为less<T>
    A.find(k)返回一个迭代器,该迭代器指向键与 k 相同的元素;如果没有找到这样的元素,则返回 a.end()
    A.lower_bound(k)返回一个迭代器,该迭代器指向第一个键不小于 k 的元素
    A.upper_bound(k)返回一个迭代器,该迭代器指向第一个键不大于 k 的元素
    A.insert(pair<KT,VT>(v,k))插入一个键值对为(v,k)的pair对象
    A.insert(p, q)插入B集合中区间[p,q)的值

    · map、multimap的使用
    #include<iostream>
    #include<set>
    using namespace std;
    
    int main()
    {
    	int arrInt[]={12,2,3,5,6};
    	int array[] = { 0, 2, 1, 4, 3, 6, 5, 7, 8, 9, 0, 7, 6};
    	map<int,int> objmap;
    	multimap<int,int>objMTmap;
    	int arrIntSize=sizeof(arrInt)/sizeof(arrInt[0]);
    	for (int i = 0; i <arrIntSize; i++)
    	{
    		objmap.insert(pair<char,int>(arrInt[i],arrInt[arrIntSize-1-i]));
    	}
    	map<int,int>::iterator objMapI=objmap.find(3);
        //find()返回迭代器类型为    map<int,int>::iterator
        //不能使用pair<char,int> objPair来获得返回值
    	objmap[12];
    	cout<<"The value of key 3 is : "<<(*objMapI).second<<endl;
        //map::iterator迭代器指向的是一个pair对象,通过first成员访问键,second成员访问值
    	
    	cin.get();
    	return 0;
    }
    
    -----输出-----
    3

无序关联容器

无序关联容器也是通过键查找值,但其通过哈希表实现,且元素也是无序的,能够快速存取元素。无序关联容器通过哈希函数计算某个对象的索引,索引相同的对象放在一个桶中,进而只在索引对应的桶中搜索。理想情况下,应有足够多的桶,每个桶只包含为数不多的对象。主要有unordered_map、unordered_set、unordered_multimap三种。

  1. 无序关联容器共有的成员
    以下表格中X表示unordered_set、unordered_map、unordered_multimap中任意一种无序关联容器。
    函数说明
    X::key_type表示键Key,类型
    X::key_equal二元谓词binary predicate,用于表示两个类型的Key参数是否相同
    X::hasherHash函数,用于计算索引值的二元函数对象
    X::local_iterator实际上是一个类型与 X::iterator 相同的迭代器,但只能用于一个桶(即一个索引)
    X::const_local_iterator实际上是一个类型与 X::const_iterator 相同的迭代器,但只能用于一个桶(即一个索引)
    X::mapped_typeunordered_map 、unordered_multimap中关联数据类型
     
    1. 无序关联容器共有的成员方法

      无序关联容器的成员方法接口与关联容器类似,拥有的方法也相近,但是没有lower_bound()、upper_bound(),因为它是无序的。需要注意的是unordered_map也支持使用[]和索引值访问桶。

      (X表示任意一种无序关联容器类型,n为无序关联容器的桶数,hf为哈希函数,A表示类X的对象,i、j为类X对象A的区间的迭代器, p、q为对象B的区间的迭代器,t为类型T对象,eq为相等谓词迭代器类型为X<T>::iterator
      函数说明
      X<KT,VT,c=less<KT>,
      Alloc=allocator<pair<KT, VT>>> A()
      创建键类型为KT、值类型为VT的无序关联容器对象A,比较对象c默认为less<T>函数对象,分配器Alloc默认为allocator<T>
      X(n, hf, eq)创建一个至少包含 n 个桶的匿名空容器,该无序关联容器将 hf 用作哈希函数,将eq用作键值相等谓词。hf默认值为 hasher(), eq默认值为key_equal()。
      X A(n, hf, eq)创建一个至少包含 n 个桶的空容器A,该无序关联容器将 hf 用作哈希函数,将eq用作键值相等谓词。hf默认值为 hasher(), eq默认值为key_equal()。
      X A(p, q, n, hf, eq)创建一个至少包含 n 个桶的空容器,将 hf 用作哈希函数,将 eq 用作键值相等谓词,并插入 区间[p, q]中的元素。n省略时桶数不定;hf默认值为 hasher(), eq默认值为key_equal()。
      X<KT,VT> A(B.begin(), B.end(), c)创建键值类型为T的set对象A,其内容为对象B的区间[begin, end)的内容,并使用函数对象c作为比较对象,c默认为less<T>
      A.find(k)返回一个迭代器,该迭代器指向键与 k 相同的元素;如果没有找到这样的元素,则返回 a.end()
      A.insert(pair<KT,VT>(v,k))插入一个键值对为(v,k)的pair对象
      A.insert(p, q)插入B集合中区间[p,q)的值
      A.hash_function()返回A使用的哈希函数
      A.key_equal()返回A使用的键值相等谓词
      A.bucket(k) 返回键值为 k 的元素所属桶的索引
      A.bucket_size(index)返回索引为index的桶的所包含的元素
      A.bucket_count()返回A包含的桶数
      A.begin(index) 返回一个迭代器,它指向索引为index的桶中的第一个元素
      A.end(index)返回一个迭代器,它指向索引为index的桶中的最后一个元素
      A.cbegin(index)返回一个常量迭代器(即const_iterator),它指向索引为index的桶中的第一个元素
      A.cend(index)返回一个迭代器,它指向索引为index的桶中的最后一个元素
      A.rehash(n)将桶数调整为不小于 n,并确保A.bucket_count() > A.size() / A.max_load_factor()
  2. 无序关联容器的使用

    与关联容器类似,代码略。

算法

STL中除了容器类的成员方法外,其还含有一些不需要使用容器类对象调用的函数,这些函数主要分为四类:
①非修改式序列操作:面向序列容器的不会修改数据的函数;
②修改式序列操作:面向序列容器的修改数据的函数;
③排序和相关操作
④通用数字运算
前三类放在头文件algorithm,第四类算法放在头文件numeric中。

一般而言,选择容器类的成员方法更加好,因为它更适用于特定容器。

(该部分等使用到了再来补!)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 STL 简介 ..............................................................................................................................................2 2 顺序性容器...........................................................................................................................................2 2.1 C++ VECTOR(向量容器) ...........................................................................................................2 2.2 C++ LIST(双向链表) .................................................................................................................4 2.3 C++ DEQUE(双向队列) ..................................................................................................................6 2.4 三者比较........................................................................................................................................8 3 关联容器...............................................................................................................................................8 3.1 特点................................................................................................................................................8 3.2 C++ SETS & MULTISETS .................................................................................................................9 3.3 C++ MAPS & MULTIMAPS ............................................................................................................ 11 4 容器适配器.........................................................................................................................................12 4.1 特点..............................................................................................................................................12 4.2 C++ STACKS(堆栈) ..................................................................................................................13 4.3 C++ QUEUES(队列) ......................................................................................................................13 4.4 C++ PRIORITY QUEUES(优先队列)...............................................................................................13 5 迭代器.................................................................................................................................................14 5.1 解释..............................................................................................................................................14 5.2 功能特点......................................................................................................................................14 6 C++标准总结..................................................................................................................................15 6.1 容器..............................................................................................................................................15 6.2 算法..............................................................................................................................................15 6.3 函数对象......................................................................................................................................17 6.4 迭代器..........................................................................................................................................19 6.5 分配器..........................................................................................................................................19 6.6 数值..............................................................................................................................................19
好的,我来为您介绍一下 C++ STL 中容器类的使用方法以及通用算法和函数对象实现查找与排序。 STL 中有多种容器类,包括 vector、list、deque、set、map 等等。这些容器类都提供了各自的操作和特点,可以根据不同的需求选择使用。 以 vector 为例,我们可以使用 push_back() 方法向其中插入元素,使用 pop_back() 方法取出末尾元素,并使用下标操作符 [] 或者迭代器访问其中的元素。示例代码如下: ```cpp #include <iostream> #include <vector> int main() { std::vector<int> v {1, 3, 4, 6, 8}; // 取出元素 while (!v.empty()) { std::cout << "取出元素 " << v.back() << std::endl; v.pop_back(); } return 0; } ``` 除了容器类之外,STL 还提供了通用算法和函数对象,可以方便地实现查找和排序等操作。比如,我们可以使用 std::find() 算法查找元素在容器中的位置,使用 std::sort() 算法对容器元素进行排序。示例代码如下: ```cpp #include <iostream> #include <vector> #include <algorithm> int main() { std::vector<int> v {1, 3, 4, 6, 8}; // 查找元素 3 的位置 auto it = std::find(v.begin(), v.end(), 3); if (it != v.end()) { std::cout << "元素 3 的位置为 " << it - v.begin() << std::endl; } // 对容器元素进行排序 std::sort(v.begin(), v.end()); // 取出元素 while (!v.empty()) { std::cout << "取出元素 " << v.front() << std::endl; v.erase(v.begin()); } return 0; } ``` 以上就是 C++ STL 中容器类的使用方法以及通用算法和函数对象实现查找与排序的介绍,希望能够对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值