八、C++ 标准模板库-STL概述

来源:互联网 发布:欧树洁面凝胶知乎 编辑:程序博客网 时间:2024/04/29 20:38

C++ 标准模板库-STL概述

一、基本概念

1.1 泛型程序设计

C++ 语言的核心优势之一就是便于软件的重用,重用在两个方面有体现:

  1. 面向对象的思想:继承和多态,标准类库
  2. 泛型程序设计(generic programming) 的思想: 模板机制,以及标准模板库 STL

简单地说就是使用模板的程序设计法。将一些常用的数据结构(比如链表,数组,二叉树)和算法(比如排序,查找)写成模板,以后则不论数据结构里放的是什么对象,算法针对什么样的对象,则都不必重新实现数据结构,重新编写算法。

标准模板库 (Standard Template Library) 就是一些常用数据结构和算法的模板的集合。有了STL,不必再写大多的标准数据结构和算法,并且可获得非常高的性能。

1.2 STL中基本的概念

容器: 可容纳各种数据类型的通用数据结构,是类模板
迭代器: 可用于依次存取容器中元素,类似于指针
算法: 用来操作容器中的元素的函数模板

二、容器概述

容器指可以用于存放各种类型的数据( 基本类型的变量,对象等)的数据结构,都是类模版,分为三种:

  1. 顺序容器
    vector, deque,list
  2. 关联容器
    set, multiset, map, multimap
  3. 容器适配器
    stack, queue, priority_queue

对象被插入容器中时,被插入的是对象的一个复制品。许多算法,比如排序,查找,要求对容器中的元素进行比较,有的容器本身就是排序的,所以,放入容器的对象所属的类,往往还应该重载 == 和 < 运算符。

2.1 顺序容器

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

vector 指动态数组。元素在内存连续存放。随机存取任何元素都能在常数时间完成,在尾端增删元素具有较佳的性能(大部分情况下是常数时间)。头文件是< vector>
vector

deque指双向队列。元素在内存连续存放。随机存取任何元素都能在常数时间完成(但次于vector)。在两端增删元素具有较佳的性能(大部分情况下是常数时间)。
deque

list指双向链表。元素在内存不连续存放。在任何位置增删元素都能在常数时间完成。 不支持随机存取。
list

2.2 关联容器

关联容器有以下几个特点:

  1. 元素是排序的
  2. 插入任何元素,都按相应的排序规则来确定其位置
  3. 在查找时具有非常好的性能
  4. 通常以平衡二叉树方式实现, 插入和检索的时间都是 O(log(N))

有两类:

  1. set/multiset(头文件 < set>)
    set 即集合。 set中不允许相同元素, multiset中允许存在相同的元素。

  2. map/multimap(头文件 < map>)
    map与set的不同在于map中存放的元素有且仅有两个成员变量,一个名为first,另一个名为second, map根据first值对元素进行从小到大排序,并可快速地根据first来检索元素。
    map同multimap的不同在于是否允许相同first值的元素

2.3 容器适配器

容器适配器有3类:stack、queue、priority_queue。

stack指栈。是项的有限序列,并满足序列中被删除、检索和修改的项只能是最近插入序列的项(栈顶的项)。 后进先出。头文件是< stack>
stack

queue指队列。插入只可以在尾部进行,删除、检索和修改只允许从头部进行。 先进先出。头文件是< queue>。
queue

priority_queue指优先级队列。最高优先级元素总是第一个出列。头文件是< queue>。

2.4 成员函数

顺序容器和关联容器中都有的成员函数:

begin 返回指向容器中第一个元素的迭代器end 返回指向容器中最后一个元素后面的位置的迭代器rbegin 返回指向容器中最后一个元素的迭代器rend 返回指向容器中第一个元素前面的位置的迭代器erase 从容器中删除一个或几个元素clear 从容器中删除所有元素front :返回容器中第一个元素的引用back : 返回容器中最后一个元素的引用push_back : 在容器末尾增加新元素pop_back : 删除容器末尾的元素erase :删除迭代器指向的元素(可能会使该迭代器失效),或删除一个区间,返回被删除元素后面的那个元素的迭代器

三、迭代器

3.1 基本概念

迭代器用于指向顺序容器和关联容器中的元素,用法和指针类似,有const 和非 const两种。通过迭代器可以读取它指向的元素,通过非const迭代器还能修改其指向的元素。

定义一个容器类的迭代器的方法可以是:

容器类名::iterator 变量名;
容器类名::const_iterator 变量名;

访问一个迭代器指向的元素:

* 迭代器变量名

迭代器上可以执行 ++ 操作, 以使其指向容器中的下一个元素。如果迭代器到达了容器中的最后一个元素的后面,此时再使用它,就会出错,类似于使用NULL或未初始化的指针一样。

3.2 迭代器示例

#include <vector>#include <iostream>using namespace std;int main() {    vector<int> v; //一个存放int元素的数组,一开始里面没有元素    v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4);    vector<int>::const_iterator i; //常量迭代器    for( i = v.begin();i != v.end();++i )        cout << * i << ",";    cout << endl;    vector<int>::reverse_iterator r; //反向迭代器    for( r = v.rbegin();r != v.rend();r++ )        cout << * r << ",";    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 << ",";}

输出:

1,2,3,4,
4,3,2,1,
100,100,100,100,

3.3 迭代器类别

3.3.1 双向迭代器

若p和p1都是双向迭代器,则可对p、 p1可进行以下操作:

++p, p++ 使p指向容器中下一个元素--p, p-- 使p指向容器中上一个元素* p 取p指向的元素p = p1 赋值p == p1 , p!= p1 判断是否相等、不等

3.3.2 随机访问迭代器

若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

3.3.3 容器和迭代器

容器 容器对应的迭代器 vector 随机访问 deque 随机访问 list 双向 set/multiset 双向 map/multimap 双向 stack 不支持迭代器 queue 不支持迭代器 priotiry_queue 不支持迭代器

四、算法简介

4.1 基本概念

算法就是一个个函数模板, 大多数在< algorithm> 中定义。

STL中提供能在各种容器中通用的算法,比如查找,排序等算法通过迭代器来操纵容器中的元素。许多算法可以对容器中的一个局部区间进行操作,因此需要两个参数,一个是起始元素的迭代器,一个是终止元素的后面一个元素的迭代器。比如,排序和查找。有的算法返回一个迭代器。比如 find() 算法,在容器中查找一个元素,并返回一个指向该元素的迭代器。

算法可以处理容器,也可以处理普通数组。

4.2 算法示例

template<class InIt, class T>InIt find(InIt first, InIt last, const T& val);

first 和 last 这两个参数都是容器的迭代器,它们给出了容器中的查找区间起点和终点[first,last)。区间的起点是位于查找范围之中的,而终点不是。 find在[first,last)查找等于val的元素用 == 运算符判断相等。

函数返回值是一个迭代器。如果找到,则该迭代器指向被找到的元素。如果找不到,则该迭代器等于last。

五、STL中“大”、“小”、“相等”的概念

5.1 基本概念

关联容器内部的元素是从小到大排序的

  1. 有些算法要求其操作的区间是从小到大排序的,称为“ 有序区间算法”
    例: binary_search
  2. 有些算法会对区间进行从小到大排序,称为“排序算法”
    例: sort
  3. 还有一些其他算法会用到“大”,“小”的概念

使用STL时,在缺省的情况下,以下三个说法等价:

  1. x比y小
  2. 表达式“ x < y”为真
  3. y比x大

关于“相等”:

  1. 有时,“ x和y相等”等价于“ x==y为真”
    例:在未排序的区间上进行的算法,如顺序查找find
    ……
  2. 有时“ x和y相等”等价于“ x小于y和y小于x同时为假”
    例:
    有序区间算法,如binary_search
    关联容器自身的成员函数find
    ……

5.2 程序示例

#include<vector>#include<algorithm>using namespace std;class A{    int v;    public:        A(int v):v(v) { }        bool operator<(const A &a) const{            cout<<v<<"<"<<a.v<<"?"<<endl;            return false;        }        bool operator==(const A &a) const{            cout<<v<<"=="<<a.v<<"?"<<endl;            return v==a.v;        }};int main(){    //重载运算符 < 后的二分查找     A a[] = {A(1), A(2), A(3), A(4), A(5)};    cout<<binary_search(a, a+5, A(9));    return 0;}

输出:

3<9?
2<9?
1<9?
9<1?
1

折半查找,最后找到1没有更多的可以找了。比较9是否小于1,结果为假;比较1是否小于9,结果为假;这时候认为9==1,输出1。

六、小结

  1. STL 三个基本概念:容器、迭代器、算法
  2. 容器分为顺序容器、关联容器、容器适配器
  3. 顺序容器分为vector(动态数组)、deque(双向队列)、list(双向链表)
  4. 关联容器分为set/multiset、map/multimap
  5. 容器适配器stack、queue、priority_queue
  6. 迭代器分为双向迭代器、随机访问迭代器,不同的容器可以使用的迭代器类别不同
  7. 算法就是一个个函数模板, 大多数在< algorithm> 中定义
  8. STL 中的”大“、”小“、”相等“等概念可以自己定义,可能和常规意义上的概念不同
0 0
原创粉丝点击