C++Primer 5th Chap9 Sequential Container

vector 可变大小数组,支持快速随机访问(在除了尾部之外部分插入删除元素很慢)
deque 双端队列,支持快速随机访问(在头尾插入删除元素很快)
list 双向链表,仅支持双向顺序访问(在任何位置插入删除元素都很快)
forward_list 单向链表,仅支持单向顺序访问(在任何位置插入删除元素都很快)
array         固定大小数组,支持快速随机访问,不能插入删除元素
string 仅支持保存字符的类似vector容器

tips:通常使用vector是最好的选择,当然如有必要也可选择其他容器

    如果不确定使用哪种容器,可以只使用vector和list公共的操作:iterator,无下标,避免随机访问

 

 iterator

  注意:forward_list不支持递减运算符(--)

  vector和string的迭代器运算同样支持deque和array

  如果begin==end,范围为空(否则范围内至少有一个元素,若干次递增begin可以使得begin==end)

容器类型成员:(详情见Chap16)

  需要元素类型,使用容器的value_type

  需要元素类型的一个引用,使用reference或const_reference

  例如: list<string>::iterator iter;

      vector<int>::difference_type count;

begin和end成员:

  //显式指定类型  list<string>::iterator it3=a.begin();

  //c++11  auto it2=a.begin();或auto it4=a.cbegin();(it4 是const_iterator)

 将一个容器初始化为另一个容器的拷贝:(要求容器类型和元素类型必须一致)

 1 #include<list>
 2 #include<vector>
 3 #include<string>
 4 #include<deque>
 5 #include<forward_list>
 6 #include<iostream>
 7 using namespace std;
 8 int main(){
 9     list<string>authors={"Milton","Shakespeare","Austen"};//c++11,列表初始化
10     vector<const char*>articles={"a","an","the"};
11     list<string> list2(authors);
12     forward_list<string>words(articles.begin(),articles.end());//可以将const char*转换为string 
13     deque<string> authList(authors.begin(),it);//假定it是authors的一个元素,拷贝范围:开始到it之前的一个元素 
14 }

 只有顺序容器的构造函数才支持大小参数(有时候得自己显式提供初始值),关联容器并不支持

  例如:vector<int> ivec(10,-9);(表示10个初始值元素的值都是-9)

标准库容器array

  必须指定固定大小:array<int,80>;

  允许对array进行拷贝和对象赋值操作(与内置数组类型不同):

    array<int,19> digits=copy;(array<int ,19>copy=/*......*/)

    array<int,19> digits=cpy;(int cpy[19]={/*............*/};) 

   

assign允许从一个不同但相容的类型赋值,或者从容器的一个子序列赋值:

  list<string> names;
  vector<const char*> oldstyles;
  names.assign(oldstyles.cbegin(),oldstyles.cend());

swap交换两个相同类型容器的内容(string类型使用swap会使其引用和指针失效,array如果使用swap时间与其元素规模成正比)

  swap只是改变了容器的数据结构,元素的值不变(只是指向该元素的容器变了)(array则正好相反)

除了无序关联容器之外的所有容器都支持关系运算符(>,<,>=,<=),只能用于相同类型容器且储存相同类型元素(而且元素本身得支持运算符)

不仅是vector,除了array和forward_list之外,所有顺序容器都支持push_back

注意:容器的元素都是拷贝(与提供该值的对象是谁无关)

list、forward_list、deque还支持push_front,将元素插入到容器头部

vector、deque、list、string还支持insert,在容器的任意位置插入元素(不同容器间的性能差距可想而知)

c++11表示:insert的接受范围或个数的版本返回值为第一个新加入元素的迭代器

  例如:list<string> lst;

     auto iter=lst.begin();

     while(cin>>word)

      iter=lst.insert(iter , word);//此举可以一直在头部添加元素

与push_back、push_front、insert对应的,c++11引入的emplace_back、emplace_front、emplace进行的是构造元素(而非拷贝元素)

  例如://c保存Sales_data元素

     //使用三个参数的Sales_data构造函数,传递给emplace成员函数的参数必需与对象的构造函数参数匹配

     c.emplace("23152415215",25,17.99);

     //等效地,构建局部临时对象

     c.push_back(Sales_data("23152415215",25,17.99));    

  

所有顺序容器都有front成员函数,除了forward_list之外的所有顺序容器都有back成员函数(分别返回首元素和尾元素的引用

  使用这两个函数或者解引用begin和end之前必须确保容器非空

  如果希望通过设置变量来改变容器中指定的元素,必须设为引用:

    auto &v=c.back();  v=20;(此时通过v改变了c的尾元素的值)

string,vector,array,deque都支持下标运算符(提供快速随机访问)

  如果希望确保下标合法,可以使用at成员函数:(如果越界则抛出异常)

    vector<string> ivec;  cout<<ivec.at(0);(等效于cout<<ivec[0];)

vector和string除了不支持push_front,也不支持pop_front(显而易见的道理)

  弹出操作要求容器必须非空(类比front和back函数),返回void(如果弹出的值仍然有用,需要再弹出前对其保存)

 搞特殊的forward_list:

  

改变容器大小:(resize不适用于array)

c.resize(n) 调整c的大小为n个元素,若n<c.size(),多余的元素被丢弃(如果必须添加新元素,则对新元素进行值初始化)
c.resize(n,t) 任何新添加的元素都初始化为t

resize缩小容器后,被删除的元素的迭代器、引用和指针都失效;对vector、string、deque进行resize操作同样可能使迭代器、引用和指针都失效

在每次添加和删除元素后重新定位迭代器是必要的(旧有的迭代器很可能失效)

不要保存end返回的迭代器,直接使用end迭代器就好(end迭代器调用的很快,也很容易失效)

  如:end=v.end();这样的行为常常导致未定义的后果

管理容量的成员函数:(shrink_to_fit只适用于vector、string、deque)

c.shrink_to_fit() 将capacity()减少为与size()相同大小(只是一个请求,不见得一定实现)
c.capacity() 不重新分配内存空间的话,c可以保存的元素数,只适用于vector和string
c.reserve(n) 分配至少能容纳n个元素的内存空间,只适用于vector和string(只有需要的空间超过当前容量时才会调用)

capacity不同于size(好比一瓶水:capacity相当于瓶子大小,size相当于已经装下的水的量)

只有迫不得已之时,容器才能分配新的内存空间

额外的string操作

  unsigned n,len2,pos2;

  string s(cp,n);//s是cp(char*类型)指向的数组中前n个字符的拷贝(如果希望完全拷贝cp,要求cp必须以空字符结束:string s(cp);)

  string s(s2,pos2);//s是string s2从下标pos2开始的字符的拷贝

  string s(s2,pos2,len2)//s是string s2从下标pos2开始len2个字符的拷贝

  substr操作:获取原string的一部分拷贝(也可以是全部)

    s.substr(pos,n);/返回一个string,从pos开始的n个字符的拷贝(pos默认为0,n默认为pos开始之后的所有字符)

   除了标准的insert和erase版本,string还提供了接受下标的版本:

    s.insert(s.size(),5,'!');//在s末尾加入5个!

    s.erase(s.size()-5,5);//从s删除最后5个字符

  string还接受c字符数组(以空字符结尾)的insert和assign版本:

    char *cp="Stately,plump Buck"

    s.assign(cp,7);//s替换为cp的头七个字符  s=="Stately"

    s.insert(s.size(),cp+7);//在s的末尾加入cp第7个字符后面的部分  s=="Stately,plump Buck"

  string还接受string的insert版本:

    string s="some string", s2="some other string"

    s.insert(0,s2);//在s的0位置之前插入s2

    s.insert(0,s2,0,s2.size());//在s的0位置之前插入从s2[0]开始到s2.size()的部分

  string的特殊函数:append和replace函数

    append是在string末尾插入的简写形式:s.append(" sth ");等价于s.insert(s.size()," sth ");

    replace是erase和insert的一种简写形式:s.replace(11,5,"Fifth");等价于s.erase(11,5);  s.insert(11,"Fifth");(插入的字符串不见得一定与删除的一样长)

string的搜索操作

  6种搜索操作都返回一个string::size_type值,表示匹配发生位置的下标(如果没找到则返回string::npos的static值)

  这些string::size_type值都是unsigned类型,所以不适合用带符号类型存储

s.find(args) 查找s中args第一次出现的位置
s.rfind(args) 查找s中args最后一次出现的位置
s.find_first_of(args) 在s中查找args中任何字符第一次出现的位置
s.find_last_of(args) 在s中查找args中任何字符最后一次出现的位置
s.find_first_not_of(args) 在s中查找第一个不在args中的字符
s.find_last_not_of(args) 在s中查找最后一不在args中的字符

  args的形式必须是以下之一:

c,pos 从s中位置pos开始查找字符c,pos默认为0
s2,pos 从s中位置pos开始查找字符串s2,pos默认为0
cp,pos 从s中位置pos开始查找c字符数组cp(以空字符结尾),pos默认为0
cp,pos,n 从s中位置pos开始查找c字符数组cp(一空字符结尾)的前n个字符,pos和n无默认值

  

 1 #include<string>
 2 #include<iostream>
 3 using namespace std;
 4 int main(){
 5     //一种常见的查找模式 
 6     string numbers("0123456789"),name("r2d2");
 7     string::size_type pos=0;
 8     while((pos=name.find_first_of(numbers,pos))!=string::npos){
 9         cout<<"found number at index: "<<pos
10             <<" element is "<<name[pos]<<endl;
11         ++pos;
12     }
13 } 

string的compare函数

  s.compare(args);根据s比另一个string等于、大于、小于,返回0,正数,负数。

  args的几种形式;

s2 比较s和s2
pos1,n1,s2 将s中从pos1开始的n1个字符与s2比较
pos1,n1,s2,pos2,n2 将s中从pos1开始的n1个字符与s2中从pos2开始的n2个字符比较
cp 比较s和cp(cp是c字符数组,以空字符结尾)
pos1,n1,cp 将s中从pos1开始的n1个字符与cp比较
pos1,n1,cp,n2 将s中从pos1开始的n1个字符与cp中的前n2个字符比较

string的数值转换

  

容器适配器

标准库定义了3个顺序容器适配器:stack、queue(此二者基于deque实现)、priority_queue(基于vector实现)

  适配器的拷贝操作:

    deque<int>deq={/*..................*/};

    stack<int> stk(deq);//从deq拷贝元素到stk

stack适配器可由除了array和forward_list之外的其他容器进行构造,queue可由list和deque构造,priority_queue可由vector和deque构造

这些适配器的使用与数据结构课上自己写的结构的使用方法一样,而且比自己写的性能更好

 

posted @ 2019-09-14 13:42  Dragonsburg  阅读(164)  评论(0编辑  收藏  举报