• 跟我学STL系列(1)——STL入门介绍


    一、引言

    最近这段时间一直都在自学C++,所以这里总结下自己这段时间的学习过程,通过这种方式来巩固自己学到的内容和以备后面复习所用,另外,希望这系列文章可以帮助到其他自学C++的朋友们。

    由于本人之前主要研究C#语言,在自学C++的过程中,经常会把C++中内容与C#中内容进行对比来理解,所以这系列文章的内容也会与C#进行比较,从而来说明语言都是想通的,只要你掌握好一门语言,学习其他语言都可以举一反三。

    二、STL是什么

    STL全称为Standard Template Library,即标准模板库,该库提供一些常用的容器对象和一些通用的算法等,大家可以理解STL就是一个库,该库帮我们封装了很多容器类和通用的方法,我们可以通过调用该库中封装好的方法和容器类来进行编程,相比C#而言,STL就好比.NET类库中的某个DLL,例如,C# 中,List<T>类存在于mscorlib.dll中System.Collections.Generic命名空间下,C++ 中,list<T>存在于list头文件中std命名空间下,所以C++代码中要使用list<T>容器(在C++中把list成为容器,即一系列元素的集合),必须先通过#include <list>引入list头文件,类似与C#中的添加mscorlib.dll引言,再使用use namespace std引入命名空间,类似与C#中using System.Collections.Generic代码。

    三、STL 六大组件

    STL通过模板抽象了基于数据结构之上的普遍行为,形成了独特的STL算法。在STL中,这些数据结构成为容器。在容器和算法之间通过中间体:迭代器来进行连接,迭代器可以看做是数据结构和算法之间的纽带,它降低了数据结构和算法之间的耦合度。STL中国又包括六大核心组件,它们分别是:

    • 容器(Container)
    • 算法(Algorithm)
    • 迭代器(Iterator)
    • 函数对象,又称仿函数(Function object)
    • 适配器(Adaptor)
    • 空间配置器(Allocator)
    下面对这六大组件分别进行介绍。

    3.1 容器

    STL中容器可分为序列式容器和关联式容器,其中,序列式容器的每个元素的位置取决于元素被插入时设置的位置,和元素值本身无关,而,关联式容器的元素位置取决于特定的排序规则,和插入顺序无关。意思就说,序列式容器中每个元素的位置与插入的顺序对应,而关联式容器中元素会根据特定的排序规则对每个元素进行排序,与元素插入的顺序无关,更多内容可以参考本系列后面文章介绍。

    序列式容器包括:vector、list和deque,而关联式容器有:set、multiset、map和multimap。下表列出了每个容器的简单介绍:
    容器 特征 内存结构 可随机存取 元素搜寻速度 头文件
    vector 在序列尾部进行插入和删除,访问和修改元素的时间复杂度为O(1),
    但插入和删除的时间复杂度与到末尾的距离成正比。
    单端数组 可以 <vector>
    list 对任意元素的访问与两端的距离成正比,但对某个位置的插入和删除
    花费为常数时间,即O(1)
    双向链表 非常慢 <list>
    deque 与vector基本相同,唯一不同的是,在序列头部插入和删除的
    时间复杂度也是O(1)
    双端数组 可以  <deque>
    set 由节点组成的红黑树,具有快速查找的功能 二叉树 <set>
    multiset 可以支持重复元素,同样具有快速查找能力 二叉树 <set>
    map 由{键,值}对组成的集合,同样具有快速查找能力 二叉树 对key而言可以 对key而言快 <map>
    multimap 一个键可以对应于多个值,同样具有快速查找能力 二叉树 对key而言快 <map>
    上面列出的所有容器在C#中都有相应的对应形式,它们之间的对应关系为:
    std::vector——List<T>
    std::list——LinkedList<T>
    std::set——HashSet<T>类,但这里需要明确,STL中的set是以红黑树作为底层数据结构,而C#中HashSet<T>类是以哈希表作为底层数据结构,因为其两者使用数据结构的不同,从而导致查询效率不同,set查找的花费时间为O(logn),这也是红黑树查询时间,而HashSet的查询花费时间为O(1)。
    std::multimap——Dictionary<TKey,List<TValue>>,该类在C#中也不存在的,也需要自己实现
    std::multiset——Dictionary<TKey,int>(第二个参数存储着Key的数量)
    C++中的std::deque在C#中并没有找到相对应地实现,不过我们可以自己实现,具体实现可以参考文章:A Deque Class in C#
    在上面的对应关系中,C#中的SortedDictionary<TKey,TValue>类是以二叉查找树作为底层数据结构的,而Dictionary<TKey,TValue>类是以哈希表作为底层数据结构的。因为其数据结构的不同从而导致操作效率的不同,下表列出了两者各种操作的区别。
    操作 Dictionary<Key,Value> SortedDictionary<Key,Value>
    this[key] O(1) O(logn)
    Add(key,value) O(1)  O(logn)
    Remove(key) O(1) O(logn)
    ContainsKey(key) O(1) O(logn)
    ContainsValue(value) O(1) O(n)

    3.2 算法

    算法是用来操作容器中数据的模板函数,它抽象了对数据结构的操作行为。要使用STL中定义的算法,应首先引入<algorithm>头文件。例如STL中的sort()函数可以对容器中的数据进行排序,可以使用find()函数来搜索容器中的某个元素。这里的算法可以与C#中泛型方法进行对比来理解。

    3.3 迭代器

    STL实现要点是将容器和算法分开,使两者彼此独立。迭代器使两个联系起来,迭代器提供访问容器中的方法。迭代器实质上是一种智能指针,它重载了->和*操作符。事实上,C++指针也是一种迭代器。在C#中同样有迭代器的概念,具体参考MSDN:http://msdn.microsoft.com/zh-cn/library/dscyy5s0(v=vs.90).aspx,不同的是,在C++ 中迭代器分为五类,这五类分别为:

    1. 输入迭代器(Input Iterator)——提供对数据的只读访问;
    2. 输出迭代器(Output Iterator)——提供对数据的只写访问;
    3. 前推迭代器(Forward Iterator)——提供对数据的读写操作,并能向前推进的迭代器;
    4. 双向迭代器(Bidirectional Iterator)——提供对数据的读写操作,并能向前和向后操作;
    5. 随机访问迭代器(Random Access Iterator)——提供对数据的读写操作,并能在数据中随机移动。

    3.4 函数对象

    函数对象,又称为仿函数,STL中的函数对象就是重载了运算符()的模板类的对象,因为该类对象的调用方式类似与函数的调用方式,所以称为函数对象,函数对象类似于C#中的委托对象,熟悉C#的朋友肯定知道,我们可以隐式地调用委托,即委托对象(实参),更多关于委托内容可以参考我的博文:委托的本质论

    3.5 适配器

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

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

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

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

    3.6 空间配置器

    当容器中保存的是用户自定义类型数据时,有的数据类型结构简单,占用的空间很小,而有的数据类型结构复杂,占用的内存空间较大;并且有的应用程序需要频繁地进行数据的插入删除操作,这样就需要对内存空间进行频繁地申请和释放工作,然而对内存的频繁操作,会产生严重的性能问题,为了解决这个问题,STL中提供了两个空间配置器,一个是简单空间配置器,仅仅对C运行库中malloc和free进行了简单的封装操作,另一个是“基于内存池的控件配置器”,即容器在每次申请内存的时候,内存池会基于一定的策略,向操作系统申请交大的内存空间,从而避免每次都向OS申请内存。STL中的空间配置器就是负责内存的分配和释放的工作。

    四、STL中容器使用示例

    看完STL组件之后,现在我们具体看看如何使用STL中的容器进行编程,下面示例是对vector容器进行简单的几个操作。具体代码如下:

    #include <iostream>  
    // 要使用vector容器必须加入vector头文件  
    #include <vector>  
    // 引入算法头文件  
    #include <algorithm>  
    // 引入std命名空间,如果不引入命名空间,则必须像std::vector这样方式来使用vector容器  
    using namespace std;  
      
    void main()  
    {  
        // 初始化vector容器对象  
        vector<int> vec;  
        for(int i=0;i<10;i++)  
        {  
            // 向vector中添加一个元素  
            vec.push_back(i);  
        }  
      
        // 使用数组初始化vector容器  
        int a[]={3,2,1,0,9,5};  
        vector<int> vec2(a,a+6); // 使用a数组第一位到第六位来初始化vector容器  
      
        // 定义迭代器对象  
        vector<int>::iterator begin;  
      
        // 遍历vector集合  
        for(begin =vec.begin();begin!=vec.end();begin++)  
        {  
            // 输出vector容器中的元素  
            cout<<*begin<<"  ";  
        }  
        cout<<endl;  
      
        // 对vec2容器排序  
        sort(vec2.begin(),vec2.end());  
        // 遍历vector集合  
        cout<<"对vec2容器排序后的结果:"<<endl;  
        for(begin =vec2.begin();begin!=vec2.end();begin++)  
        {  
            // 输出排序后vec2容器中的元素    
            cout<<*begin<<"  ";  
        }  
        cout<<endl;  
    }  

    上面代码的输出结果如下图所示:

    五、小结

    该篇博文只是对STL进行一个全面的介绍,希望初学者对STL能有一个全面的认识,并且本文对于一些难懂的内容,都用C#中相关的内容进行了解释,如果有像我一样,之前学习C#朋友可以对比来进行理解,关于STL六大组件的详细介绍会在后面文章进行介绍。
     
    PS:这里需要说明的一点,本人开始学习C++,并不是因为C#语言不行,用大牛的一句说就是:语言只是工具,用来实现你思考的工具,重要在于思想和遇到问题的解决方式,并且希望通过C++的学习可以对一些底层的东西可以有一个更深入的认识,因为C#封装的太好,确实我们要去了解底层会有点难,但是并不说不可以,其实它们之间说白了也是差不多的,只是C++可以更好地去了解底层的一些操作罢了,并且我学习的过程,时刻与C#进行对比来进行理解C++的内容,相信这也是一个对C#的巩固的过程。
     
  • 相关阅读:
    ActiveMQ的消息模式——队列模式(Queue)
    在foxmail上添加阿里邮箱
    Neither the JAVA_HOME nor the JRE_HOME environment variable is defined 错误解决
    博客园首页新随笔联系管理订阅订阅随笔- 89 文章- 0 评论- 3 Centos7开放及查看端口
    tomcat设置为开机自启动
    Tensorflow2疑难问题---2、tensorflow2.3的GPU版本安装
    Tensorflow2疑难问题---1、课程介绍
    tensorflow2的gpu的版本安装(一些核心点)
    此环境变量太大, 此对话框允许将值设置为最长2047个字符(解决方法)
    windows下cuda的安装
  • 原文地址:https://www.cnblogs.com/zhili/p/STLIntroduce.html
Copyright © 2020-2023  润新知