STL标准程序库总结二(容器及迭代器)

1 容器的共通能力

  三个核心能力:

(1)      所有容器都提供value语意而非reference语意

(2)      总体而言所有元素形成一个次序

(3)      一般而言各项操作并非绝对安全

2容器的共通操作

每个容器类都提供一个default构造函数一个copy构造函数和一个析构函数



3        Vector容器

(1)Vector的赋值操作

C1=C2

   C.assign(n,elem):复制n个elem赋值给C

   C.assign(beg,end):将区间【beg,end】内的元素赋值给C

   C.swap(C1);

   Swap(c1,c2):全局

(2)元素存取

  C.at(index): 返回索引index所标示的元素如果index越界抛出越界异常

  C[index]:不检查越界

  C.front():返回第一个元素。不检查第一个元素是否存在

  C.Back():。。。。。。。。。。。。。。。

(3) 迭代器相关的函数:

C.begin(),C.end(),C.rbegin(),C.rend();

(4)安插和移除操作

  迭代器必须指向一个合法的位置区间的起始位置不能在结束位置之后决不能从空容器中移除元素

下列移除操作性能会比较快

在容器尾部安插或移除元素

容器一开始就足够大

安插多个元素时调用一次比调用多次快

Vector的操作:

c.insert(pos,elem)

c.insert(pos,n,elem)

c.insert(pos,beg,end):在pos位置插入区间元素

c.push_back(elem);

c.pop_back()

c.erase(pos);

c.erase(beg,end);

c.resize(num):将元素数量改为num如果size()变大了多出来的元素多需要default构造函数完成

c.resize(num,elem)多出来的元素都是elem副本

c.clear()

(5)Classvector<bool>

C++ 标准程序库针对元素类别bool的vector设计了一个特殊版本目的是获取一个优化的vector,vector<bool>可能比一般的vector慢些,因为所有的元素操作都必须转化为bit操作

Vector<bool>的特殊操作

c.flip():将所有的bool元素取反值即求补码

m[index].flip():某一位取反

m[index]=value;

m[index]=m[index2];

4Deques容器

以下情形最好用deque容器:

(1)      你需要在两端安插元素

(2)无需引用容器内的元素

(3)要求容器释放不再使用的元素

Vector 和deques的接口几乎一样

以下数点与vector不同:

1 deques不提供容量操作(capacity和reserve)

1        deques 直接提供函数用以完成头部函数的安插和删除(push_front(),pop_front())

5 List容器

Lists与vector或deque的不同

(1)      Lists不支持随机存取

(2)      任何位置上执行元素的安插和移除速度都很快

(3)      安插和删除元素动作并不会造成指向其它元素的各个pointer,reference,iterators失效

(4)      Lists 对于异常有着这样的处理方式:要么操作成功要么什么都不发生

Lists的操作函数:

元素的存取:

c.front():返回第一个元素

c.back():返回最后一个元素

迭代器相关函数:

只有运用迭代器才能够存取list中的各个元素

元素的安插和移除lists提供deques的所有功能还增加了remove()和remove_if()算法应用于list身上的特殊版本

c.remove_if(op)移除所有造成op(elem)结果为true的元素

c.remove(value)移除所有其值为value的值

Lists的特殊变动性操作函数


含义区别:

size()目前存在的元素数。           元素个数

capacity()容器能存储数据的个数     容器容量

reserve()指定容器能存储数据的个数

resize()  重新指定有效元素的个数,区别与reserve()指定容量的大小

当创建空容器时,容量(capacity) 0;当用完时,增加原容量的 1/2 (各编译器可能存在差异  vs2010是这样的,mingw增加原容量--适用如 vector这种元素连续存储的容器,如为list则不同。

capacity一般大于size的原因是为了避免每次增加数据时都要重新分配内存,所以一般会生成一个较大的空间,以便随后的数据插入。

 

6  Sets和Multisets

Sets不允许重复而Multisets允许重复

Set的排序准则:

(1)      必须是“反对称的”如果x<y为真则x>y为假

(2)      必须是可以传递的x<y,y<z则x<z

(3)      必须是非自反的 x<x永远为假

Set的结构为平衡二叉树自动排序的主要优点是具有良好的性能

Set和MultiSet不提供用来直接存取元素的操作函数

通过迭代器进行元素间的直接存取有一个限制:从迭代器的角度看元素的值是常数

6.2Sets和multisets的操作函数

Set c;

Set c(op)以op为准则产生一个空的set或multisets

Set C1(C2)

Set  C(beg,end);

Set C(beg,end,op)

c.~set()

两种方式定义排序准则:

(1)     以template参数定义之例如:template<int,std::greater<int>>col

(2)     以构造函数参数定义之

非变动性操作:

和一般容器相似

特殊的搜索函数:

Count(elem):返回元素值为elem的元素个数

Find(elem)

Lower_bound(elem):返回elem第一个可以安置的位置也就是说元素值>=elem的第一个元素位置

Upper_bound(elem)

Equal_range(elem):返回elem可安插的第一个元素的位置和最后一个位置也就是元素值==elem的元素区间

Set 和Multisets的安插和移除:



安插函数的返回值型别不尽相同:

Set 提供如下接口:

Pair<iterator,bool>insert(const value_type&elem);

Iterator insert(iterator pos_hint,constvalue_type& elem);

Multisets提供如下接口:

Iterator insert(const value_type& elem);

Iterator insert(iterator pos_hint, constvalue_type& elem);

返回值型别不同的原因,multisets允许元素重复而sets不允许,set的返回值型别是以pair组织起来的两个值

在pair结构中的second成员表示安插是否成功

Pair结构中first成员返回新元素的位置。或返回现存的同值元素的位置,其他任何情况函数都返回新元素的位置

如果multset内含重复元素你不能使用erase()删除这些重复的元素你可以这么做

Set::multiset<elem>::iteratorpos;

Pos=coll.find(elem);

If(pos!=coll.end())

Coll.erase(pos);

序列式容器:

Iterator erase(iterator pos);

关联式容器:

Void erase(iterator pos)

 

 

 

 

 

 

 

 

 

 

7 Map和Multimaps

元素具备条件:

(1)      key/Value 必须具备assignable(可赋值)和copyable(可复制)

(2)      对排序准则而言,key必须是compareable(可比较的)

7.1 Maps和Multimaps的能力

  你不可以直接改变元素的key因为这会破坏正确的次序要修改元素的key你必须移除拥有该key的元素,然后插入拥有新的key/value的元素

7.2操作函数

两种方式定义排序准则:

(1)      以template参数定义

例如:std::map<folat,std::string,std::greater<folat>>coll

(2)      构造函数参数定义

详见例子

   2非变动性操作同一般序列

2        Maps和Multimaps 的特殊搜索函数

Count(key)

Find(key)

Lower_bound(key)

Upper_bound(key)

Equal_range(key)

3        maps和Multimaps只支持所有容器提供的基本赋值操作:

C1=C2

C1.swap(C2)

Swap(c1,c2)

4        迭代器函数和元素存取

在map和multimap中,所有元素的key都被视为常数。因此元素的实质类型是pair<const key,T>.这个限制是为确保你不会因为变更元素的key而破坏以排好序的元素次序

如果你一定要改变元素的key只有一条路:以一个”value相同的元素”替换掉旧元素

Maps提供了一种非常方便的手法让你改变元素的key像下面这样

Coll[“new_key”]=coll[“old_key”];

Coll.erase(“old_key”);

5        元素的安插和移除

 

三个不同的方法将vlaue传入map

(1)      运用value_type

避免隐式类型转换你可以利用value_type明白传递正确的型别value_type是容器本身提供的类型定义

Std::map<syd::string,float>coll

Coll.insert(std::map<std::string,float>::value_type(“otto”,12.5));

(2)      运用pair<>

Coll.insert(std::pair<conststd::string,float>(“oto”,12.5));

(3)      运用make_pair();

Coll.insert(std::make_pair(“otto”,12.5));

移除“迭代器所指元素”的正确做法

For(pos=coll.begin();pos!=coll.end();)

  If(pos->second==value)

      Coll.erase(pos++)

Else

  ++pos

7.3 将Maps视为关联式数组

M[key]:返回一个reference指向键值为key的元素如果元素不存在则安插

 

 

STL其他容器

使你的容器STL化的三种不同方法

1The invasive approach(侵入性方法)

 直接提供STL容器所需接口

2the noninvasive approach

 由你拟写或提供特殊迭代器作为算法和特殊容器的界面

3the wrapper approach 包装法

 将上述方法组合我们可以写一个外套类别来包装任何数据结构并显示出和STL容器相似的接口

7.4 各种容器的运行时机

容器的使用选择:

(1)     缺省情况下应该使用vector。

(2)     如果经常要在序列头部和尾部安插和移除元素应该采用deque

(3)     如果需要经常在容器的中段执行元素的安插,移除和移动可考虑使用list

(4)     如果你容器是这种性质“每次操作若不成功便无效”那么你可以用list

(5)     如果你经常需要根据某个准则来搜寻元素,那么应当使用“以该排序准则”对元素进行排序的set或者是multiset

(6)     如果处理key/value pair 请采用map/multimap(或者哈希表)

(7)     如果需要关联数组请使用map

(8)     如果需要字典结果请使用multimap

 

STL容器能力一览:





7.5 细说容器内的型别和成员

 

Container::reference

(1)     元素的引用型别典型定义container::value_type& 在vector<bool>中是个辅助类别

Container::size_type

无正负号整数型别,用于定义容器大小

Container::difference_type 有正负号用于定义距离

Container::key_compare 关联式容器的元素内的value型别

Contianer::allocator_type 配置器的型别

7.6 STL异常处理

七迭代器

7.1 迭代器的分类及能力

Input 迭代器   向前读取能力   供应者 istream

Output 迭代器   向前写入             ostream

Forward 迭代器  向前读取和写入      

Bidlrectional    向前和向后读取和写入  容器

Random access   随机存取可读取也可写入 


尽可能的优先选用前置式递增操作符++iter因为性能好


是否有效或写入动作是否成功你唯一做的就是写入写入在写入


       Bidirectional 迭代器在forWard迭代器的基础上增加了回头遍历能力它支持递减运算符—iter ;iter—

Randomaccess 迭代器在bidirectional迭代器的基础上增加了随机存储能力


Vector迭代器的递增和递减

迭代器的递增和递减操作是个奇怪的问题一般而言你可以递增或递减暂时性的迭代器但是对已vector和string就不行。

Std::vector<int>coll

If(coll.size()>1)

Sort(++coll.begin(),coll.end());

通常编译sort()时就会失败如果用deque取代就没事因为vector的迭代器被实做一般的指针C++不允许你修改任何基本型别(包括指针)的暂时值但对于自定义类型没事

所以以上程序需改为:

Std::vector<int>::iteratorbeg=coll.begin();

7.2 迭代器相关辅助函数

C++标准库为迭代器提供三个辅助函数:advance(),distance()iter_swap()

前二者提供给所有迭代器一些原本只有Random access 才有的能力

7.2.1Advance()可令迭代器前进

Voidadvance(inputIterator&pos,Dist n)

使名为pos的Input的迭代器步进n个元素对Bidirectional迭代器很容Randomaccss而言n可以为负数代表后退

Advance()并不检查迭代器是否超过序列的end()所以调用advance()有可能导致未定义行为。

    list<int>coll;

    for(inti=1;i<=9;i++)

        coll.push_back(i);

    list<int>::iterator pos=coll.begin();

    cout<<*pos<<endl;

    advance(pos,3);

    cout<<*pos<<endl;

    advance(pos,-1);

    cout<<*pos<<endl;

7.2.2distance()函数

Dist distance(inputiterator pos1,inputiterator pos2)

传回pos1和pos2之间的距离

两个迭代器必须指向同一个容器如果不是random access迭代器则从pos1开始往前走必须能够达到pos2亦即pos2的位置必须与pos1相同或其后

返回的dist型别由迭代器决定iterator_traits<inputiteraotr >::different

list<int>coll;

    for(inti=-3;i<9;++i)

        coll.push_back(i);

    list<int>::iterator pos;

    pos=find(coll.begin(),coll.end(),5);

    if(pos!=coll.end())

        cout<<"difference between bengin and 5"<<distance(coll.begin(),pos)<<endl;

7.2.3iter_swap()可交换迭代器所指元素的内容

Void iter_swap(ForwardIteratorpos1,Forwarditerator pos2)

交换迭代器pos1和pos2所指的值

迭代器的型别不必相同但其所指的两个值必须可以相互赋值

7.3 迭代器配接器

此特殊迭代器可以使得算法能够

以逆向模式(reverse)安插模式(insert mode)进行工作也可以和stream搭配工作

7.41Reverse 迭代器

Reverse迭代器是一种配接器重新定义递增和递减运算使其正好倒置算法将逆序处理元素

    for_each(coll.rbegin(),coll.rend(),print);

rbegin()和rend()传回一个Reverse迭代器

你可以将一般iterator 转化为一个Reverse iterator但然原本的那个iterator必须具有双向移动能力转化前后迭代器的逻辑位置发生变化

方式转化:vector<int>::reverse_iterator rpos(pos);



以base()将逆向迭代器转化为正常迭代器逆向迭代器提供一个base()函数

 

7.3.2insert(安插型)迭代器

 Insert迭代器用来将赋值新值操作转化为安插新值,通过这种迭代器算法可以执行安插行为而非覆盖行为

Insert迭代器通常使用下面两个实例技巧

(1)                             被视作为一个无实际的动作只是简单传回*this所以对insert迭代器来说*pos与pos等价

(2)                             赋值动作被转化为安插操作

所以对于一个insert迭代器你可以写pos=value也可写*pos=value

Insert迭代器的操作

*iter无实际操作传回iter

Iter=value安插value

++iter无实际操作

Iter++无实际操作

7.3.3Insert迭代器种类

Backinserter  类back_insert_iterator   调用push_back()    生成函数back_inserter(cont)

Frontinserter   front_insert_iterator    调用push_front()         front_inserter(cont)

Generalinserter  insert_iterator           insert(pos,value)         inserter(cont,value)

Backinsert的实例:

 

vector<int>coll;

    back_insert_iterator<vector<int>>iter(coll);

    *iter=1;

    iter++;

    *iter=2;

    iter++;

    iter=3;

    for_each(coll.begin(),coll.end(),print);

    back_inserter(coll)=45;

    back_inserter(coll)=46;

    for_each(coll.begin(),coll.end(),print);

    coll.reserve(2*coll.size());

    copy(coll.begin(),coll.end(),back_inserter(coll));

    for_each(coll.begin(),coll.end(),print);

注意:一定要在调用copy()函数之前确保有足够的空间因为在安插元素时可能会造成指向该vector的其他迭代器失效

7.3.3Stream流迭代器

Stream迭代器是一种迭代器配接器一个istream配接器可以从Input流中读取元素一个

Ostream迭代器的各项操作:

Ostream_iterator<T>(ostream)为ostream产生一个ostream迭代器

Ostream_iterator<T>(ostream,delim)各元素间以delim分割

*iter    无实际操作

Iter=value将value写到ostream像这样ostream<<value

++iter   无实际操作

Iter++   无实际操作

对于istream还有:iter1==iter2 检查iter1和iter2是否相等

Iter1!=iter2

Istream_iterator<T>()产生一个end_of_stream 迭代器

Iter->number    传回先前读取的元素的成员

实例:

vector<int>coll;

    back_insert_iterator<vector<int>>iter(coll);

    istream_iterator<int>intreader(cin);

    istream_iterator<int>intRederoff;

    while(intreader!=intRederoff)

    {

        cout<<"once:"<<*intreader<<endl;

                ++intreader;

    }

输入 1 2 3 f 4

结果:1 2 3

字符f的输入导致程序的结束是的由于格式错误stream不在出去good状态

7.5 迭代器的特性

7.5.1为迭代器编写泛型函数

通过迭代器特征你可以拟写这样的泛型函数:根据迭代器类的型别而派生型别定义或采取不同的实作码

(1)      运用迭代器型别

暂时变量可以声明如下:

Typenamestd::iterator_traits<T>::value_type tmp;

(2)运用迭代器类型

      如果希望针对不同的迭代器类型采取不同的实作方案可以采取下面步骤

      2.1让你的template函数将迭代器类型作为附加参数,调用另一个函数

      Template<class iterator>

      Inline void foo(iterator beg,iteratorend)

       {

         Foo(beg,end,std::iterator_traits<iterator>::iterator_category())

}

2.2针对不同的迭代器类型实作出上述所调用的函数。只有“并非派生自其它迭代器类型”的迭代器类型,才需要提供特殊化版本

Template<classBiIteraor>

Void foo(BiIteratorbeg,BiIterator)

例子distance()的实作

//general distance



7.4使用者自定义的迭代器

要求:

1)       提供必须要的五种型别定义就想iterator_traits结构中所描述的

Template<classT>

Structiterator_traits{

Typedef typename T::value_type        value_type;

Typedef typename T::defference_type     difference_type;

Typedef typename T::iterator_category     iterator_category;

Typedef typename T::pointer             pointer;

Typedef typename T::reference           reference;

};

2)       提供一个iterator_traits结构

关于第一中C++标准库提供特殊基类iterator<>专门用来这类定义

Class my_iterator:public std::iterator<std::bidirectional_iterator_tag,type,std::ptrdiff_t,

Type*,type&>

{};

第一个迭代器类型就是iterator_traits所用的成员,最后三个是默认参数

关键实例:

template<classContainer>

classasso_insert_iteraotr:publicstd::iterator<std::output_iterator_tag,void,void,void,void>

{

protected:

    Container& container;

public:

    explicitasso_insert_iteraotr(Container&c):container(c)

    {}

    asso_insert_iteraotr<Container>&operator=(consttypenameContainer::value_type&value)

    {

        container.insert(value);

        return*this;

    }

    asso_insert_iteraotr<Container>&operator*()

    {

        return*this;

    }

    asso_insert_iteraotr<Container>&operator++()

    {

        return*this;

    }

    asso_insert_iteraotr<Container>&operator++(int)

    {

        return*this;

    }

};

 

template<classContainer>

inlineasso_insert_iteraotr<Container>asso_inserter(Container&c)

{

    returnasso_insert_iteraotr<Container>(c);

}

 

 

void main()

{

    set<int>coll;

    asso_insert_iteraotr<set<int>>iter(coll);

    *iter=1;

    ++iter;

    *iter=2;

    for_each(coll.begin(),coll.end(),print);

    cout<<endl;

    asso_inserter(coll)=44;

    asso_inserter(coll)=55;

    for_each(coll.begin(),coll.end(),print);

    cout<<endl;

    intvalues[]={33,6,4,12,-23,2};

    copy(values,values+(sizeof(values)/sizeof(values[0])),asso_inserter(coll));

    for_each(coll.begin(),coll.end(),print);

    cout<<endl;

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STL(Standard Template Library)是C++标准程序库中的一个重要组成部分,提供了一套模板类和函数,用于支持通用的数据结构和算法。STL标准程序库开发指南旨在帮助开发人员更好地理解和使用STL库。 首先,STL库包含多个模板类,如vector、list、queue、map等,可以用于存储和操作不同类型的数据。这些类使用了模板元编程的概念,可以根据不同的数据类型生成对应的类实例。开发人员可以根据实际需求选择适合的容器类,并使用类似于数组的方式进行数据的访问和操作。 其次,STL库提供了一系列的算法,如排序、查找、复制、删除等,可以在容器类上进行操作。这些算法是经过优化和测试的,可以提供高效的性能,并且可以处理通用的数据类型。开发人员可以直接调用这些算法,而无需自己实现相应的功能,提高了开发效率。 此外,STL库还提供了的概念,通过可以访问容器中的元素。开发人员可以使用来遍历容器,进行元素的读取和修改,并且可以通过实现算法的传递和组合。可以提供与容器的解耦合,使得容器的具体实现可以灵活替换,而不会影响到使用的代码。 最后,STL库还定义了一些辅助类和函数,如函数对象、分配等,可以方便地扩展和定制库的功能。开发人员可以根据具体的需求,自定义函数对象或选择合适的分配,以满足不同的场景需求。 总之,STL标准程序库开发指南是一本帮助开发人员更好地学习和应用STL库的指南。通过深入理解STL库的设计原理和使用方法,开发人员可以更加高效地开发C++程序,并且能够借助STL库提供的丰富功能,实现各种数据结构和算法的应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值