zoukankan      html  css  js  c++  java
  • C++ Templates STL标准模板库的基本概念

    STL标准库包括几个重要的组件:容器、迭代器和算法。迭代器iterator,用来在一个对象群集的元素上进行遍历操作。这个对象群集或许是一个容器,或许是容器的一部分。迭代器的主要好处是,为所有的容器提供了一组很小的公共接口。利用这个接口,某项操作就可以行进到群集的下一个元素。同时每一种容器都提供了自己的迭代器,而这些迭代器了解该种容器的内部结构,所以能够知道如何正确行进。

    vector是将其元素置于一个dynamic array 中加以管理。它允许随机存取,也就是说你可以利用索引直接存取任何一个元素。在array尾部附加元素或者移除元素均非常快速。但是在array中部或者头部安插元素就比较费时,因为,为了保持原本的相对次序,安插点之后的所有元素都必须移动,搬出位子来。
    vector和deque都有这几个函数
    push_back()向后插入元素
    push_front()向前插入元素
    size()成员函数返回容器中的元素个数

    List由双向链表(double linked list)实作而成。这意味着list内的每个元素都以一部分内存指示其前驱元素和后继元素。List不提供随机存取,因此如果你要存取第10个元素,你必须沿着串链一次走过前9个元素。不过,移动至下一个元素或前一个元素的行为,可以在常数时间内完成。因此一般的元素存取动作会花费线性时间。这比vector和deque提供的分摊时间(amoritzed)常数时间,性能差很多。
    List的优势是:在任何位置上执行安插或删除动作都非常迅速,因为只需改变链接就行。这表示在list中间位置移动元素比在vector和deque快得多。
    list 函数申明:
    front();
    empty();
    push_back();
    pop_front();//并不会返回被删除的元素,所以你无法将front()和pop_front()合二为一

    vector没有提供push_front(),因为其时间性能很差,在vector头端安插一个元素,需要移动全部的元素。一般而言,stl容器只提供
    通常具备良好的时间效能的成员函数,这样可以防止程序员调用性能很差的函数。
    #include<iostream>
    #include<list>
    using namespace std;
    int main()
    {
    list<char>coll;//list container for character elements
    for(char c='a';c<='z';c++)
    {
    coll.push_back(c);
    }
    while(!coll.empty())
    {
    cout<<coll.front()<<' ';
    coll.pop_front();
    }
    cout<<endl;
    }

    也可以吧string当做STL容器来使用。这里的string是指c++string类族系(basic_string<>,string,wstring)的对象。string和vector非常相似,只不过其元素为字符。

    Array容器不是类别class,而是c++语言核心所支持的一种type,具有静态大小或者动态大小的
    array。但是array并非stl容器,他们并没有类似size()和empty()等成员函数。尽管如此,stl的设计允许你针对array调用stl算法,当我们以static arrays作为初始行时,这一点特别有用。

    关联容器和顺序容器的本质区别:关联容器是通过键存取和读取元素、顺序容器通过元素在容器中的位置顺序存储和访问元素。因此,关联容器不提供front、push_front、pop_front、back、push_back以及pop_back,此外对于关联容器不能通过容器大小来定义,因为这样的话将无法知道键所对应的值什么。
    关联式容器依据特定的排序准则,自动为其元素排序。排序准则一函数形式呈现,用来标记哦元素值(value)或者元素键(key)。缺省情况下以operator<进行比较,不过你也可以提供自己的比较函数,定义出不同的排序准则。


    两个基本的关联容器类型是map和set。map的元素以键-值对的形式组织:键用作元素在map的索引,而值则表示所存储和读取的数据。set仅包含一个键,并有效地支持关于某个键是否存在的查询。set和map类型的对象不允许为同一个键添加第二个元素。如果一个键必须对应多个实例,则需使用multimap或mutiset类型,这两种类型允许多个元素拥有相同的键。

    ps:所有的关联式容器都提供有一个insert()成员函数,用以安插新元素
    在关联式容器中不能使用序列式容器的push_back()和push_front()函数,它们在这里毫无意义,因为你没有权利制定新元素的位置。并且要注意的是Sets不允许存在重复元素

    迭代器(iterator)是一个可遍历STL容器内全部或部分元素的对象。一个迭代器用来指出容器中的一个特定位置。基本操作如下:
    Operator*
    返回当前位置上的元素值。如果该元素拥有成员,你可以透过迭代器,直接以operator->取用

    Operator++
    将迭代器前进至下一个元素。大多数迭代器还可以使用operator--退回前一个元素。

    Operator==和Operator!=
    判断两个迭代器是否指向同一位置

    operator=
    为迭代器赋值(将其所指元素的位置赋值过去)

    这些操作和c++操作array元素是的指针接口一致。不同之处在于,迭代器是个所谓的smart pointer,具有遍历复杂数据结构的能力。其下层运行机制取决于其所遍历的数据结构。因此,每一种容器都需要将其迭代器以嵌套的方式定义与内部。因此各种迭代器的接口相同,型号却不同。这直接导致了泛型程序设计的概念:所有操作行为都使用相同的接口,虽然他们的型号不同。因此,你可以使用template将泛型操作公式化,使之得以顺利的运行那些能够满足接口需求的任何型别。
    所有的容器类别都提供有一些成员函数,使我们得以获得迭代器并以之遍历所有的元素。这些函数中最重要的是:
    begin():返回一个迭代器,指向容器起始点,也就是第一元素所在的位置。
    end():返回一个迭代器,指向容器的结束点。结束点在最后一个元素之后,这样的迭代器又称为past-the-end 迭代器。
    1、为遍历元素时,循环的结束时机提供了一个简单的判断依据。只要尚未到达end(),循环就可以继续
    2、不必对空区间采取特殊的处理方法。空区间的begin()就等同于end();

    #include<iostream>
    #include<list>
    using namespace std;
    int main()
    {
    list<char>coll;
    for(char c='a';c<='z';++c)
    {
    coll.push_back(c);
    }
    list<char>::const_iterator pos;
    for(pos=coll.begin();pos!=coll.end(); ++pos)
    {
    cout<<*pos<<" ";
    }
    cout<<endl;
    return 0;
    }

    任何一种容器都定义有两种迭代器型别:
    1、container::iterator
    这种迭代器以“读/写”的模式遍历元素
    2、container::const_iterator
    这种迭代器以”只读“模式

    在循环内部,语句*pos代表当前的元素。本例将它输出之后,又接着输出了一个空格。你不能改变元素内容,以为pos是个const_iterator,从迭代器的观点看去,元素是常量,不能改变。不过如果拟采用非常量(nonconstant)迭代器,而且元素本身的型别也是非常量,那么就可以透过迭代器来改变元素的值。
    list<char>::iterator pos;
    for(pos=coll.begin();pos!=coll.end();++pos)
    {
    *pos=toupper(*pos);
    }//最好使用++pos,不要使用pos++

    我们也可以采用list例中所用的相同循环来打印set内的元素。以一个迭代器遍历全部元素,并且逐一打印出来:
    IntSet::const_iterator pos;
    for(pos=coll.begin();pos!=coll.end();++pos)
    {
    cout<<*pos<<" ";
    }

    由于迭代器是容器定义的,所以无论容器内部结构如何复杂,它都知道如何行事。举个例子,如果迭代器指向第三个元素,操作符++便会将它移动到上端的第四个元素,再一次++,便会将它移动到下方的第五个元素。


    set中元素输出默认是从小到大(set不可以有重复元素)  如这个set的输出结果就是:1 2 3 4 5 6 


    #include<iostream>
    #include<set>
    using namespace std;
    int main()
    {
    typedef set<int>IntSet;//元素型别为int的一个set
    IntSet coll;
    coll.insert(1);
    coll.insert(3);
    coll.insert(5);
    coll.insert(4);
    coll.insert(1);
    coll.insert(6);
    coll.insert(2);
    IntSet::const_iterator pos;
    for(pos=coll.begin();pos!=coll.end();pos++)
    {
    cout<<*pos<<" ";
    }
    cout<<endl;
    return 0;
    }
    set中的元素组织形式都是一种类似二叉树的依次排列
    由于multiset允许元素重复存在,因此其中可包含两个数值相同的元素
    新元素会根据排序准则自动安插到正确的位置。但是,你不能使用序列式容器的push_back()和push_front()函数,在这里毫无意义,因为你没有权利指定新元素的位置。

    Maps和Multimaps的运用实例

    Map的元素是成对的键值/实值(key/value)。因此其申明、元素安插、元素存取皆和set有所不同。下面是一个multimap的运用实例
    #include<iostream>
    #include<map>
    #include<stirng>
    using namespace std;
    int main()
    {
    typedef multimap<int,stirng> IntStringMMap;
    IntStringMMap coll;
    coll.insert(make_pair(5,"tagged"));
    coll.insert(make_pair(2,"a"));
    coll.insert(make_pair(1,"this"));
    coll.insert(make_pair(4,"of"));
    coll.insert(make_pair(6,"strings"));
    coll.insert(make_pair(1,"is"));
    coll.insert(make_pair(3,"multimap"));
    IntStringMMap::iterator pos;
    for(pos=coll.begin();pos!=coll.end();++pos)
    {
    cout<<pos->second;
    }//不过由于this和is的键值相同,两者的出现顺序也可能反过来
    cout<<endl;
    }
    输出结果:this is a multimap of tagged strings

    //c++标准程序库凡是必须返回两个值的函数,也都会利用pair对象。pair可以将两个值视为一个单元。容器类别map和multimap就是使用pairs来管理其健值/实值(key/value)的成对元素
    pair的实现是一个结构体,主要的两个成员变量是first second, 因为是使用struct不是class,所以可以直接使用pair的成员变量。

  • 相关阅读:
    [BZOJ4631]踩气球
    [BZOJ1998][Hnoi2010]Fsk物品调度
    [BZOJ3624][Apio2008]免费道路
    [BZOJ1064][Noi2008]假面舞会
    [BZOJ4154][Ipsc2015]Generating Synergy
    [BZOJ1941][Sdoi2010]Hide and Seek
    [BZOJ2850]巧克力王国
    [BZOJ2683][BZOJ4066]简单题
    万年历(calendar)
    SACD ISO镜像中提取DSDIFF(DFF)、DSF文件
  • 原文地址:https://www.cnblogs.com/guohaoyu110/p/6443939.html
Copyright © 2011-2022 走看看