STL 基础学习总结

来源:互联网 发布:北京知果科技 编辑:程序博客网 时间:2024/06/05 11:49

0 什么是STL

STL(Standard Template Library)就是标准模板库。STL是泛型编程的实例,用到的技术就是类模板和函数模板。STL的一个重要特点是数据结构和算法的分离。

1 模板概念

模板就是一种使用无类型的参数来产生一系列函数或类。通过模板可以产生类或函数的集合,使它们操作不同的数据类型,从而避免需要为每一种数据类型产生一个独立的类或函数。

函数模板:独立于类型的函数,可产生函数的特定版本;

类模板:跟类相关的模板,如vector,可产生类对特定类型的版本,如vector<int>

典型的函数模板:

求两个数的最大值:

template <class T>

T max(T a,T b)

{

return(a>b)?a,b;

}

函数模板只是说明,并不能直接执行,需要进行实例化以后才能执行。

模板优点:

1) 克服了C语言上使用不同函数表达相似功能的坏习惯;

2) 克服了C++使用函数重载的繁琐;

模板缺点: 调试比较困难

1  STL六大组件

1.1 容器

容器是可容纳各种数据类型的数据结构。

标准库中定义了两种标准的容器:

顺序容器(Sequence

顺序容器的每个元素的位置取决于元素被插入时设置的位置,和元素值本身无关。顺序容器包括:vector、list和deque;

向量 vector

后部插入/删除,直接访问

链表 list

双向链表,任意位置插入/删除

双向队列 deque

/后部插入/删除,直接访问

 

关联容器 (Associative container)

关联容器中元素会根据特定的排序规则对每个元素进行排序,与元素插入的顺序无关。关联式容器有:set、multiset、map和multimap。

map

一对一映射,无重复元素,基于关键字查找

multimap

一对一映射,可有重复元素,基于关键字查找

set

快速查找,无重复元素

multiset

快速查找,可有重复元素

 

1.2 算法

算法是用来操作容器中数据的模板函数,它抽象了对数据结构的操作行为。要使用STL中定义的算法,应首先引入<algorithm>头文件。例如find()用来搜索一个list中的对象,用sort()来对一个vector中的数据进行排序。

算法可以对容器的内容提供不同方式的操作,包括查找、排序、复制、匹配以及元素重组等。

主要有4种类型的算法

1) 非变易算法,该类算法不对所作用的容器进行任何修改。

算法比较典型的是find()count()for_each等;

2) 变易算法,这类算法的特点是会对它们所作用的容器进行修改。

比较有代表性的算法包括copy()reverse()等;

3) 排序算法,这类算法的特点是对容器进行不同方式的排序,

这类算法比较典型的是sort()upper_bound()等;

4) 数值算法,它们主要对容器的内容进行数值计算,

这一类算法主要包括accumulate()adjacent_difference()等。

1.3 迭代器

STL实现要点是将容器和算法分开,使两者彼此独立。迭代器使两个联系起来,迭代器提供访问容器中的方法。

访问容器中的元素:

容器::iterator iter;

for(iter= 容器.begin();iter!=容器.end();iter++)

{

cout<<*iter 或者 iter->first       

}

 

迭代器可分为五种类型

1. 输入迭代器(Input Iterator——提供对数据的只读访问;

只能一次一个向前读取元素,按此顺序一个个传回元素值。Input迭代器只能读取元素一次,如果你复制Input迭代器,并使原Input迭代器与新产生的副本都向前读取,可能会遍历到不同的值。下表列出了Input迭代器的各种操作行为。

表达式

功能表述

*iter 

读取实际元素

iter->member   

读取实际元素的成员

++iter

向前步进(传回新位置)

iter++    

向前步进(传回旧位置)

iter1 == iter2

判断两个迭代器是否相同

iter1 != iter2

判断两个迭代器是否不相等

 

2. 输出迭代器(Output Iterator——提供对数据的只写访问;

Output迭代器和Input迭代器相反,其作用是将元素值一个个写入。operator*只有在赋值语句的左手边才有效。无法检验Output迭代器是否有效,或“写入动作”是否成功。你唯一可以做的就是写入、写入、再写入。下表列出了Output迭代器的有效操作

表达式 

功能表述

*iter = value

将元素写入到迭代器所指位置

++iter 

向前步进(传回新位置)

iter++   

向前步进(传回旧位置)

 

3. 前推迭代器(Forward Iterator——提供对数据的读写操作,并能向前推进的迭代器;

Forward迭代器是Input迭代器与Output迭代器的结合,具有Input迭代器的全部功能和Output迭代器的大部分功能。Forward迭代器能多次指向同一群集中的同一元素,并能多次处理同一元素。下表总结了Forward迭代器的所有操作。

表达式 

功能表述

*iter 

存取实际元素

iter->member   

存取实际元素的成员

++iter 

向前步进(传回新位置)

iter++  

向前步进(传回旧位置)

iter1 == iter2 

判断两个迭代器是否相同

iter1 != iter2

判断两个迭代器是否不相等

iter1 == iter2

复制             

 

4. 双向迭代器(Bidirectional Iterator——提供对数据的读写操作,并能向前和向后操作;

双向迭代器在Forward迭代器的基础上增加了回头遍历的能力。它支持递减操作符,用以一步一步的后退操作

 

5. 随机访问迭代器(Random Access Iterator——提供对数据的读写操作,并能在数据中随机移动。

Random Access迭代器在Bidirectional迭代器的基础上再增加随机存取能力。因此它必须提供迭代器算数运算。以下对象支持Random Access迭代器:

    可随机存取的容器(vector, deque

    strings(字符串,stringwstring

一般array(指针)

1.4 适配器

适配器是用来修改其他组件接口,与设计模式中的适配器模的达到的效果是一样的。STL中定义了3种形式的适配器:容器适配器、迭代器适配器和函数适配器。

容器适配器——包括栈(stack)、队列(queue)和优先队列(priority_queue),容器适配器是对基本容器类型进行进一步的封装,从而转换为新的接口类型。

 

迭代器适配器——对STL中基本迭代器的功能进行扩展,该类适配器包括反向迭代器、插入迭代器和流迭代器。

函数适配器——通过转换或修改来扩展其他函数对象的功能。该类适配器有否定器、绑定器和函数指针适配器。函数对象适配器的作用就是使函数转化为函数对象,或将多参数的函数对象转换为少参数的函数对象。

1.5 空间配置器

当容器中保存的是用户自定义类型数据时,有的数据类型结构简单,占用的空间很小,而有的数据类型结构复杂,占用的内存空间较大;并且有的应用程序需要频繁地进行数据的插入删除操作,这样就需要对内存空间进行频繁地申请和释放工作,然而对内存的频繁操作,会产生严重的性能问题。

为了解决这个问题,STL中提供了两个空间配置器

一个是简单空间配置器,仅仅对C运行库中mallocfree进行了简单的封

装操作;

另一个是基于内存池的控件配置器,即容器在每次申请内存的时候,内存池会基于一定的策略,向操作系统申请较大的内存空间,从而避免每次都向OS申请内存。

STL中的空间配置器就是负责内存的分配和释放的工作。

1.6 函数对象

函数对象,又称为仿函数,STL中的函数对象就是重载了运算符()的模板类的对象,因为该类对象的调用方式类似于函数的调用方式,所以称为函数对象。

2 四种类型转换操作符

1. static_cast:将一个值以符合逻辑的方式转换。

应用到类的指针上,意思是说它允许子类类型的指针转换为父类类型的指针,同时,也能够执行相反动作:转换父类为它的子类。

例如:float x;

      Count<<static_cast<int>(x);//把x作为整型值输出

 

2. dynamic_cast:将多态类型向下转换为其实际静态类型。

只用于对象的指针和引用。当用于多态类型时,它允许任意的隐式类型转换以及相反过程。dynamic_cast会检查操作是否有效。也就是说,它会检查转换是否会返回一个被请求的有效的完整对象。检测在运行时进行。如果被转换的指针不是一个被请求的有效完整的对象指针,返回值为NULL。

例如:

class Car;  

class Cabriolet:public Car

{  

…  

};  

void f(Car *cp)  

{  

Cabriolet *p = dynamic_cast< Cabriolet > cp;  

}

 

3. reinterpret_cast:转换一个指针为其它类型的指针。

它也允许从一个指针转换为整数类型。反之亦然。这个操作符能够在非相关的类型之间转换。操作结果只是简单的从一个指针到别的指针的值的二进制拷贝。在类型之间指向的内容不做任何类型的检查和转换。

例如:

    class A {};  

    class B {};  

    A *a = new A;  

    B *b = reinterpret_cast<B *>(a);  

 

4.  const_cast一般用于强制消除对象的常量性。

例如:

    class C {};  

    const C *a = new C;  

C *b = const_cast<C *>(a);  

 

 

 

0 0
原创粉丝点击