STL组件概述

一、六大组件
容器、类属算法、迭代器、函数对象、适配器、分配器

二、容器(存储其他对象集合的对象)
1.序列容器(将一组具有相同类型的对象以严格线性的形式组织在一起)
  • vector<T>:随机访问编程序列,即:访问复杂度为O(1),对序列末尾的插入和删除均是分摊常量;(数组表示
  • deque<T>:随机访问边长序列,对序列开头和末尾的插入和删除操作均是分摊常量的;(两级数组结构实现
  • list<T>:(双向链表)对变长序列的线性时间访问;对序列中任意位置的插入和删除操作时间复杂度为O(1);(双向链表实现
:(1)对于string类和STL序列容器类,其end成员函数返回的是终点之后的迭代器,而不是真正指向序列最后一个元素的迭代器;
(2)STL为所有容器类都定义了==运算符;

2.有序关联容器(有从基于键的集合中快速提取对象的能力,集合的大小可运行时改变)
  • set<Key>:支持唯一的键(每个键只出现一次),并可快速检索键;
  • multi<Key>:支持可重复的键(同一个键可出现多次),可快速检索键key 
  • map<Key,T>:键值对,支持唯一的键可通过键快速检索其对应的类型为T的值;(用find(Key)数据成员实现)
  • multimap<Key,T>:键值对,支持可重复的键;可通过键快速检索其对应的类型为T的值;
例,向map中插入元素:
map<string , long> map_test;
map_test["cyj"]=123;

注意:STL容器和其他C++容器类库的重要区别之一:STL容器类并没有为其所含的数据提供过多的操作,而是提供了类属算法

三、类属算法
1.类属查找算法(适用于任何STL容器)
  • find(iterator1 , iterator2, search_content):若找到,返回第一个出现search_content的位置,否则返回容器某位元素后面一个元素的迭代器;
    例:
    vector<char> vec1 = make<vector<char> >("C++");
    find(vec1.begin|(),vec1.end(),'C');
注:与表(list)对应的迭代器不支持+运算符,支持自增预算符++;所有STL容器均支持自增预算符++

2.类属合并算法(merge,将两个序列内的元素合并到一个序列中)
  • 调用形式
    merge(  first1 , last1 , first2 , last2, result );
    (1) 迭代器first1和last1表示一个输入序列的起始和终止位置,元素类型为T;
    (2)迭代器first2和last2表示另一个输入序列的起始和终止位置,元素类型为T;

    (3)两个输入序列均为升序排列

    (4)result表示合并序列存放的起始位置注意:结果容器所有元素均升序排列;若前面两个容器中元素均未升序排列,合并后的result容器非升序排列;三个容器不一定是同一类容器,可以属于不同类别,如:分别为list,char[] , deque容器,但元素类型必须为T;
例子:
#include <cassert>
2 #include <iostream>
3 #include <deque>
4 #include <list>
5 #include <algorithm>
6 #include "string.h"
7 #include "stdlib.h"
8 using namespace std;

10 template<typename container>
11 container make( const char source[]);
12 
13 int main()
14 {
15 char s[]="acd";(升序)
16 int len = strlen(s);
17 list<char> list1 = make< list<char> >("befghijklmnopqrstuvwxy");(升序)
18 deque<char> d(26,'x');
19 
20 merge(&s[0],&s[len] , list1.begin() , list1.end(),d.begin());
assert( d == make< deque<char> >("abcdefghijklmnopqrstuvwxyx"));
23 std::cout<<"result ok"<<std::endl;
24 return 0;
25 }
26 
27 
28 template<typename container>
29 container make( const char source[])
30 {
31 return container( &source[0] , &source[strlen(source)]);
32 }


四 迭代器(具有和指针类似的特征)


1.迭代器分类
  • 输入迭代器:支持!=,*,++,==,但是对于*操作,只能从容器中读取数据,而不能向其中写入数据
  • 输出迭代器:支持!=,*,++,==,但是对于*操作,不能从容器中读取数据,只能向其中写入数据
  • 前向迭代器:支持==,!= , *,++操作;
  • 双向迭代器:支持==,!= , *,++,--操作;
  • 随机访问迭代器:支持==,!= , *,++,--,+=,-=,+,-,<,>,<=,>=操作
  • 类属函数accumulate:accumulate(first,last,init),把init和从first到last指向的值进行累加并返回累加得到的和;
注意:accumulate、find、merge等一些用于输入地带器的算法比对迭代器有更高要求的算法(如sort算法要求使用随机访问迭代器)通用性强。


五、函数对象
  • 函数对象:一个实体,可以不带参数,也可以带有一个以上的参数,并能够从中获得一个值或改变程序的状态,除了普通函数,另一类函数对象可以是类或结构的对象,且在其定义中重载了函数调用运算符
例子:
#include <iostream>
2 #include <vector>
3 #include <algorithm>
4 #include <numeric> //for accumulate

6 using namespace std;
7
//函数对象,重载函数调用运算符。
8 class multi{
9 public:
10 //function call overload
11 int operator()(int x , int y ) const
12 {
13 return x*y;
14 }
15 };
16 
17 int main()
18 {
19 int x[5]={1,2,3,4,5};
20 vector<int> vec1(&x[0],&x[5]);
//1 is inited value
22 int result = accumulate(vec1.begin() , vec1.end() , 1, multi());
23 std::cout<<"result is:"<<result<<std::endl;
24 }

  • 在类multi中定义函数调用运算符operator(),就定义了一种可以作为函数参数的对象,可以像使用函数一样使用该对象;multi()使用编译器提供的默认构造函数;该对象没有响应的内存,只有函数定义;
  • 函数对象的优势
    (1)以类的形式定义函数对象,可以携带更多额外信息,某些类属算法或容器将会用到这类信息;
    (2)更加通用、高效

六、适配器(改变其他组件接口的组件)
  • 适配器reverse_iterator:将某种类型的迭代器变成一种新的迭代器,但保持其功能不变,将其遍历的方向翻转过来。(使用场景:如用find函数查找某个元素在容器中最后出现的位置;浮点数累加,若元素升序排列,舍入误差通常会小一些,否则,以降序顺序排列时,与累加和相比,非常小的数值对于累加和几乎不起任何作用,因此可用reverse_iterator和accumulate实现降序序列浮点数累加,结果精确些)
  • 注:STL每种容器都定义了reverse_iterator,以及返回这种类型迭代器的rbegin和rend成员函数
  • 栈适配器:将序列容器变换到先进后出的栈接口中;
  • 队列适配器:将序列容器变换到先入先出队列中;
  • 优先级队列:将序列容器变换到优先级队列中,由一个比较参数来控制元素访问顺序。
  • 函数适配器:
    (1)取反器(negator):对判定函数对象(返回值为bool类型)的结果进行取反;
    (2)绑定器(binder):将二元函数的一个参数与某个特定的值绑定,从而将二元函数编程一元函数。
    (3)函数指针适配器:从函数指针得到函数对象。

七、分配器(封装程序所用的内存分配模式信息)
注:分配器类可以封装许多信息:指针、常量指针、引用、常量引用、对象大小、不同类型指针之间的差别、分配函数与释放函数以及其他一些函数信息。分配器上所有操作都具有分摊常量的运行时间
posted @ 2015-05-24 16:48  cyjseagull  阅读(381)  评论(0编辑  收藏  举报