标准模板STL-概述

2018-12-31  本文已影响0人  gpfworld
1. STL
(1)先回忆数据结构
从数据结构的学习中,我知道了有顺序表,链表,哈希表,顺序树,链式数等数据结
构可以用于存放数据。

在c中,这些数据结构都需要程序员自己实现,但是在面向对象的语言中,为了节省编
程者的开发时间,都提供了自己的定义的现成可用的数据结构,这些数据结构本质上还
是数组,链表,树(红黑树),哈希表等等。


(2)一个数据结构包含哪些内容
以我们之前学习的链表这个数据结构为例,它包含如下内容。

(1)容器:链表就是一个存放数据的容器,存储结构为链式存储,存放数据时,
    需要反映出被存储数据的逻辑结构

(2)遍历:向前向后索引节点就是遍历,遍历节点是能够访问数据的前提。当然对于
    遍历操作来说,除了可以使用迭代器外。

(3)算法:对链表中的数据的具体操作算法,增加,删除,查找,修改,排序

实际上对于高级语言自带的数据结构做的也是这些事情,但是这些事情不需要程序员
操心,我们只要学会使用就好,有了这些现成的数据结构,我们甚至都可以省去使用
自定义数组,因为这些数据结构本身就可以替代数组的功能。某些数据结构中本身就
是数组。

(1)c++的STL模板库与java中的集合
对于哪些封装好的现成可用的数据结构在c++中叫STL,java中称为集合,实际上是一
个东西,对于这些现成的数据结构来说,同样涉及如下三个方面的内容:

(1)容器

(2)遍历:普通指针,迭代器(智能指针),在c++和java都有迭代器,实现原理也
    是一样。

(3)算法:针对操作容器的算法,可以有如下3情况
    (1)可以自己实现操作容器的算法,实际上这么做没有必要
    (2)容器提供成员函数方式实现的算法
    (3)STL模板库提供全局算法函数
    
    
对于容器和集合的学习,重点在于学习怎么使用容器,比通过提供的算法去操作容器中
的数据。

不管是c++还是java的定义的数据结构,都是用到了泛型,在c++称为模板(函数模板和
类模板)。


2. 容器/迭代器/算法
(1)STL容器:
(1)存放内容的方式
    (1)存放副本:存放副本的特点是,修改副本并不会修改原对象的内容。

    (2)存放指针:使用指针好处是,效率很高,比存放副本的方式效率高很多。

    在java中没有存放副本的做法,存放的都是指针。

(2)STL容器分类
    (1)序列容器:以线性方式组织管理存放的数据,STL提供的顺序容器有:

        (1)vector<T>:以数组方式实现的数据结构,空间开辟于堆,
                其大小和容量可以根据实际情况改变。
        (2)deque<T>:可以在两头操作的特殊vector。
        (3)list<T>:使用链表实现的数据结构。
        (4)stack:栈,使用较少       
            (5)queue:队列,使用较少
        (6)priority_queue:优先队列,使用较少  



    (2)关联容器:使用键值(key)与存储的内容关联起来,通过key去访问容
        器的中内容。STL提供的关联容器有:

        (1)map<key, T>:容器中一部分用于存放key值(key值不能重复)。
                另一部分用于存放key值对应的数据,把我们把
                Key和对应的数据我们称为键值对。

        (2)multimap<key, T>:同map,但是key值可以重复。

        (3)set<key>:数据本身就是key值,要求内容不能重复。

        (4)multiset<key>:同set,但是内容可以重复。 
                
    在c++这只提供了线性容器和关联容器这两类,但是在java提供了更加丰富的容器,
    (1)线性容器:vector,list,队列等
    (2)非线性容器:树(tree)结构的容器   
    (3)关联容器:map和set



(2)STL迭代器(普通指针)
(1)什么是迭代器
    迭代器就是封装好的智能指针,在学习前面的课程中,我们知道,智能指针
    就是对指针做了类封装的,c和c++中的指针就是最简单的迭代器。

(2)按功能对迭代器进行分类
    从功能上按照简单到复杂的顺序,迭代器分为如下及种类型,复杂类型的迭
    代器兼容简单类型的迭代器。

    (1)输入输出迭代器
        (1)用于读写一系列的对象,输入迭代器只能进行读操作,输出
            迭代只能进行写操作。
        (2)只能使用一次,第二次使用需要重新创建
        (3)实现的操作有:前后++,==,!=,*
        
    (2)前向迭代器
        兼容输入输出迭代器的功能,可以多次使用向前迭代器读写容器
        中的对象,迭代器支持++操作(前++/后++都支持)。
    
    (3)双向迭代器
        兼容前向迭代器的功能,但同时还允许向后遍历对象。所以迭代器
        还支持前后--的操作(前--/后--都支持)。
    
    (4)随机迭代器
        兼容双向迭代器的功能,但是同时允许随机访问。因为支持随机访
        问,所以必须支持如下操作:
        (1)iter+n和iter-n操作,iter[n]等价于*(iter+n)
        (2)iter+=n和iter-=n操作
        (3)迭代器相减,iter1-iter2操作
        (4)迭代器比较操作,比如iter1<iter2,iter1>iter2,
            iter1<=iter2,iter1>=iter2操作。
    
    以上功能是累积的,输入输出迭代器功能最弱,随机迭代器功能最强。
        

(3)在迭代器中使用泛型的问题
    定义迭代器对象时,需要指定访问的数据类型,比如:
        std::vector<int>::iterator iter;
    如果类型是泛型的话,定义迭代器是必须使用typename关键字,否者将会无法使用,比如:
        typename std::vector<T>::iterator iter;
    
    如果使用typedef给迭代器类型起别名时,如果涉及到泛型,那么同样的也需要使用
    typename关键字,比如:
        typedef typename std::vector<T>::iterator Iter;
        Iter iter;//使用别名定义迭代器


(3)如何获取迭代器
    (1)自定义迭代器,自定义迭代器可以按照自己要求实现以上4种类型中需要类型的迭代器。

    (2)从容器中获取迭代器
        STL容器自己提供了访问容器的迭代器。
        容器:     提供的迭代器类型
        vector                  随机              
        deque                   随机         
        list                    双向
        set                     双向 
        multiset                双向             
        map                     双向
        multimap            双向                        
        stack                   不支持迭代器                  
        queue               不支持迭代器
        priority_queue      不支持迭代器

        vector和deque之所以可以随机访问,因为他们本质上都是数组,我们前面讲过,数组
        本身就支持随机访问。
        
        list本质是链表,链表是不支持随机访问。

        set和map专门用于存放集合类数据,也是不支持随机访问的。

        栈,队列,优先队列之所以没有迭代器,因为都是在它们的头尾进行操作的,不需要遍
        历和随机访问。

    (3)使用容器以外迭代器
        比如iostream,istream, ostream, sstream等输入输出流提供的迭代器。



(3)算法函数
(1)容器提供的成员算法函数
    每种容器都提供了哪些成员算法函数,将在后面讲解,成员算法函数中,有些是直接定义的
    函数,有些就是通过函数模板实现的。

    容器提供的成员算法函数只针对本容器进行的。

(2)全局算法函数
    (1)查找类
        find(),find_end(),adjacent_find(),count(), mismatch(),
        seaech(), equal()。

    (2)修改类
        swap(), copy(), transform(). replace(), remove(), reverse(),
        rotate(), fill(), random/_shffle()。

    (3)排序
        sort() stable_sort(), binary_search(), merage(), min(), 
        max(), lexicographical_compare()。


    实际上一些普通的修改,查找等操作,直接通遍历访问每个元素就可以实现,
    不需要使用这些算法函数。全局算法函数大多都是通过函数模板实现的。
        
    全局算法函数可以针对不同种类的容器进行操作,但是也有些容器是无法通过
    全局算法函数无法操作的,这个时候只能通过容器的成员算法函数进行操作。
    

(4)STL的头文件
(1)容器头文件
    <vector>(单端数组), <deque>(双端数组), <list>, <map>, <set>, 
    <queque>(双端队列),<stack>(栈)   

(2)迭代器头文件
    <iterator>
    
    但是由于容器使用到了迭代器,因此容器头文件中也有包含<iterator>头文
    件,包含容器头文件时,可以不用包含迭代器头文件。    

    如果使用到了输入输出流提供的迭代器,需要包含输入输出流的头文件,比
    如<iostream>, <istream>, <ostream>,<sstream>。
    
(3)全局算法涉及头文件
    <algorithm>

    如果涉及函数对象,还需要<functional>头文件。
上一篇下一篇

猜你喜欢

热点阅读