[置顶] C++ Primer 学习笔记_28_STL实践与分析(2) --顺序容器的操作(上)



STL实践与分析

--顺序容器的操作()



引:

每种顺序容器都提供了一组有用的类型定义以及以下操作:

    1)在容器内添加元素;

    2)在容器中删除元素;

    3)设置容器的大小;

    4)(如果有的话)获取容器内的第一个和最后一个元素。


正文:

一、容器定义的类型别名

所有容器都提供的类型别名

size_type

无符号整型,足以存储容器类型的最大可能容器长度

iterator

容器的迭代器类型

const_iterator

容器的只读迭代器类型

reverse_iterator

按逆序寻址元素的迭代器类型

const_reverse_iterator

元素的只读逆序迭代器

difference_type

足够存储两个迭代器差值的有符号整型,可为负数

value_type

元素类型

reference

元素的左值类型,是value_type&的同义词

const_reference

元素的常量左值类型,等效于constvalue_type&

    逆序迭代器从后向前遍历容器,并反转了某些相关的迭代器操作,例如,在逆序迭代器上做++运 算将指向容器中的前一个元素。

表中最后三种类型使程序员无须直接知道容器元素的真正类型,就能使用它。需要使用元素类型时,只要用value_type即可。如果要引用该类型,则通过referenceconst_reference类型实现。在程序员编写自己的泛型程序时,这些元素相关类型的定义非常有用

    使用容器定义类型的表达式看上去非常复杂

[cpp] view plain copy print ?
  1. vector<string>::iterator iter;  
  2. vector<int>::difference_type cnt;  

[cpp] view plain copy print ?
  1. //P273 习题9.16  
  2. //int型的vector容器应该使用的索引类型为vector<int>::size_type  

[cpp] view plain copy print ?
  1. //习题9.17  
  2. /* 
  3. *正序 
  4. */  
  5.     list<string>::iterator  
  6.     list<string>::const_iterator  
  7. /* 
  8. *逆序 
  9. */   
  10.     list<string>::reverse_iterator  
  11.     list<string>::const_reverse_iterator  

二、beginend成员

容器的beginend成员

c.begin()

返回一个迭代器,它指向容器c的第一个元素

c.end()

返回一个迭代器,它指向容器c最后一个元素的下一位置

c.rbegin()

返回一个逆序迭代器,它指向容器c最后一个元素

而不是下一位置!

c.rend()

返回一个逆序迭代器,它指向容器c第一个元素前面的位置

而不是第一个元素!

    上述每个操作都有两个不同版本:一个是const成员,另一个是非 const成员这些操作返回什么类型取决于容器是否为const。如果容器不是const,则这些操作返回iteratorreverse_iterator类型。如果容器是 const,则其返回类型要加上const_前缀,也就是const_iteratorconst_reverse_iterator类型


三、在顺序容器中添加元素


在顺序容器中添加元素的操作

c.push_back()

在容器c的尾部添加值为t的元素。返回void类型

c.push_front()

在容器c前端插入值为t的元素。返回void类型。

只适用于listdeque容器类型。

c.insert(p,t)

在迭代器p所指向的元素前面插入值为t的新元素,返回指向新添加元素的迭代器。

c.insert(p,n,t)

在迭代器p所指向的元素前面插入n个值为t的新元素,返回void

c.insert(p,b,e)

在迭代器p所指向的元素前面插入迭代器be标记的范围内的元素,返回void

【关键概念】容器元素都是副本

     在容器中添加元素时,系统是将元素值复制到容器里。类似地,使用一段元素初始化新容器时,新容器存放的是原始元素的副本被复制的原始值与新容器中的元素各不相关,此后,容器内元素值发生变化时,被复制的原值不会受到影响,反之亦然。【P274

[cpp] view plain copy print ?
  1. list<int> iList;  
  2. for (int i = 0; i != 10; ++i)  
  3. {  
  4.     iList.push_back(i);  
  5.     iList.push_front(i);  
  6. }  
  7. for (list<int>::const_iterator iter = iList.begin(); iter != iList.end(); ++iter)  
  8. {  
  9.     cout << *iter << endl;  
  10. }  

1、在容器中的指定位置添加元素

[cpp] view plain copy print ?
  1. vector<string> strVec;  
  2. list<string> strList;  
  3. string val("Beth");  
  4.   
  5. //  strList.insert(strList.begin(),val);  
  6. strList.push_front(val);  
  7. strVec.insert(strVec.begin(),val);  //这个操作的代价是很昂贵的  

2、插入一段元素

[cpp] view plain copy print ?
  1. //1  
  2. vector<string> strVec;  
  3. strVec.insert(strVec.end(),10,"Ha~");  
  4.   
  5.    //2  
  6.    list<string> strList;  
  7.    vector<string> strVec;  
  8.    string sarray[4] = {"quasi","simba","frollo","scar"};  
  9.   
  10.    strList.insert(strList.end(),sarray,sarray+4);  
  11.    strVec.insert(strVec.end(),strList.begin(),strList.end());  

3、添加元素可能会使迭代器失效

     vector容器中添加元素可能会导致整个容器的重新加载,这样的话,该容器所涉及到的所有迭代器都会失效!即使不需要重新加载整个容器,指向新插入元素后面的迭代器也会失效

任何insertpush操作都可能导致迭代器失效,因此在编写循环将元素插入到vectordeque容器中时,程序必须确保迭代器在每次循环后都得到更新。


4、避免存储end操作返回的迭代器

    在容器的任何位置插入任何元素都会使end迭代器失效!!!

[cpp] view plain copy print ?
  1.     vector<int>::iterator first = iVec.begin(),  
  2.                           last = iVec.end();  
  3.   
  4.     //程序运行期间可能崩溃  
  5.     while (first != last)  
  6.     {  
  7.         first = iVec.insert(++first,42);  
  8.         ++ first;  
  9.     }  
  10. /* 
  11. *添加元素会使得存储在last中的迭代器失效, 
  12. *该迭代器既没有指向容器iVec的元素, 
  13. *也不再指向iVec的超出末端的下一个位置 
  14. */  

[cpp] view plain copy print ?
  1. //正确的写法  
  2.    vector<int>::iterator first = iVec.begin();  
  3.   
  4. while (first != iVec.end())  
  5. {  
  6.     first = iVec.insert(++first,42);  
  7.     ++ first;  
  8. }  

[cpp] view plain copy print ?
  1. //P276 习题9.18  
  2. int main()  
  3. {  
  4.     list<int> iList;  
  5.     for (int i = 0; i != 55; ++i)  
  6.     {  
  7.         iList.push_front(i+1);  
  8.     }  
  9.   
  10.     deque<int> iDeq1,iDeq2;  
  11.   
  12.     for (list<int>::iterator iter = iList.begin(); iter != iList.end(); ++iter)  
  13.     {  
  14.         if (*iter % 2)  
  15.         {  
  16.             iDeq1.push_front(*iter);  
  17.         }  
  18.         else  
  19.         {  
  20.             iDeq2.push_front(*iter);  
  21.         }  
  22.     }  
  23.   
  24.     cout << "iDeq1:" << endl;  
  25.     for (deque<int>::iterator iter = iDeq1.begin(); iter != iDeq1.end(); ++iter)  
  26.     {  
  27.         cout << *iter << '\t';  
  28.     }  
  29.     cout << endl << "iDeq2:" << endl;  
  30.     for (deque<int>::iterator iter = iDeq2.begin(); iter != iDeq2.end(); ++iter)  
  31.     {  
  32.         cout << *iter << '\t';  
  33.     }  
  34.     cout << endl;  
  35. }  

四、关系操作符

 所有的容器类型都支持用关系操作符来实现两个容器的比较。比较的容器必须具有相同的容器类型,而且其元素类型也必须相同。例如,vector<int> 容器只能与vector<int>容器比较,而不能与list<int>vector<double>容器比较。

      容器的比较是基于容器内元素的比较。容器的比较使用了元素类型定义的同一个关系操作符:两个容器做!=比较使用了其元素类型定义的!=操作符。如果容器的元素类型不支持某种操作符,则该容器就不能做这种比较运算。

下面的操作类似于string类型的关系运算:

    •如果两个容器具有相同的长度而且所有元素都相等,那么这两个容器就相等;否则,它们就不相等。

    •如果两个容器的长度不相同,较短的容器中所有元素都等于较长容器中对应的元素,则称较短的容器小于另一个容器。

    •如果两个容器都不是对方的初始子序列,则它们的比较结果取决于所比较的第一个不相等的元素

[cpp] view plain copy print ?
  1. vector<Sales_item> storeA;  
  2. vector<Sales_item> storeB;  
  3. if (storeA < storeB) // error  

[cpp] view plain copy print ?
  1. //P278 习题9.20  
  2. int compVecList(const vector<int> &iVec,const list<int> &iList)  
  3. {  
  4.     vector<int> tmp(iList.begin(),iList.end());  
  5.   
  6.     if (iVec > tmp)  
  7.         return 1;  
  8.     else if (iVec < tmp)  
  9.         return -1;  
  10.     return 0;  
  11. }  
  12.   
  13. int main()  
  14. {  
  15.     vector<int> iVec;  
  16.     list<int> iList;  
  17.     for (int i = 0; i != 10; ++i)  
  18.     {  
  19.         iVec.push_back(i);  
  20.         iList.push_back(i);  
  21.     }  
  22.     iList.push_back(11);  
  23.   
  24.     cout << compVecList(iVec,iList) << endl;  
  25. }  

五、容器大小的操作

所有容器都提供的大小操作

c.size()

返回容器c中的元素个数。返回类型为c::size_type

c.max_size()

返回容器c可容纳的最多元素个数,返回类型为c::size_type

c.empty()

返回标记容器大小是否为0的布尔值

c.resize(n)

调整容器c的长度大小,使其能容纳n个元素,如果n<c.size(), 则删除多出来的元素;否则,添加采用值初始化的新元素

c.resize(n,t)

调整容器c的长度大小,使其能容纳n个元素。所有新添加的元素值都为t


[cpp] view plain copy print ?
  1. void printList(const list<int> &iList)  
  2. {  
  3.     for (list<int>::const_iterator iter = iList.begin(); iter != iList.end(); ++iter)  
  4.     {  
  5.         cout << *iter << '\t';  
  6.     }  
  7.     cout << endl;  
  8. }  
  9. int main()  
  10. {  
  11.     list<int> iList(10,42);  
  12.     printList(iList);  
  13.     iList.resize(15);  
  14.     printList(iList);  
  15.     iList.resize(25,-1);  
  16.     printList(iList);  
  17.     iList.resize(5);  
  18.     printList(iList);  
  19. }  

    使用resize操作可能会使迭代器失效,在vectordeque容器上做的resize操作有可能会使得所有的迭代器都失效!

    对于所有的容器类型,如果resize操作压缩了容器,则指向已删除的元素的迭代器会失效!

你可能感兴趣的:(C++,添加元素,顺序容器,关系操作,容器大小)