C++ Primer 第九章顺序容器

Posted shadowhu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ Primer 第九章顺序容器相关的知识,希望对你有一定的参考价值。

一、综述

<vector>:可变大小数组。支持快速随机访问。在尾部之外的位置插入或删除元素可能很慢。

<deque>:双端队列。支持快速随机访问。在头尾位置插入/删除速度很快。

<list>:双向链表。只支持双向顺序访问。在list中任何位置进行插入/删除操作速度都很快。

<forward_list>:单向链表。只支持单向顺序访问。在链表任何位置进行插入/删除操作速度都很快。

<array>:固定大小数组。支持快速随机访问。不能添加或删除元素。

<string>:与vector相似的容器,但专门用于保存字符。随机访问快。在尾部插入/删除速度快。

 

通常用vector是最好的选择。其次list。

 

二、迭代器

  1. begin指向首元素,end指向尾元素之后。
  • begin == end,vector为空
  • begin != end,至少有一个元素

 

  • 类型是iterator
  • cbegin和cend的类型是const_iterator(不需要做写访问时 )
  • rbegin和rend的类型是reverse_iterator
  • 还有crbegin => const_reverse_iterator

 

  1. 定义一个迭代器

  vector<int>::iterator iter;

 

三、容器的定义和初始化

  • vector<int> vec1(vec2);

   vector<int>vec1 = vec2;  【将vec1初始化为vec2的拷贝

  • vector<string> svec{"a", "b", "c"};
  • vector<string> svec={"a", "b", "c"};    【将vec初始化为列表中的元素拷贝
  • vector<int> vec1(b, e);    【初始化为迭代器b, e(直到但不包括)之中的元素拷贝
  • vector<int> seq(n);    【seq包含n个元素
  • vector<int> seq(n, t);    【seq包含n个值为t的元素

 

特殊:定义array

array<int, 42>;    【要指定大小,包含42个int的数组

 

四、赋值与swap

  • array<int, 10> = {0};    【全置为0
  • array<int, 10> = {0,1,2,3,4,5,6,7,8,9};    【列表赋值
  • swap(c1, c2);

   c1.swap(c2);    【交换c1与c2,比拷贝快,

  • 只要类型一样就可以,连同size完全交换
  • 迭代器、指针、引用还是在原来的容器上,不会跟着交换

 

特别的:对于顺序容器,assign

vectorString.assign(listChar.begin(), listChar.end()); 【将一个char型的list拷贝到string型的vector里

 

五、顺序容器的操作

  1. 添加元素(非array,因为array固定大小,forward_list比较特殊)
  • c.push_back(t);    【在c的尾部添加一个值为t或者由args创建的元素。return void

   c.emplace_back(args);    【forward_list不支持push_back

  • c.push_front(t);    【vector和string不支持push_front,但是可以用insert插入到c.begin()之前

   c.emplace_front(args);    【在c的头部添加一个值为t或者由args创建的元素。return void

  • c.insert(p, t);

   c.emplace(p, args);    【在迭代器p指向的元素之前插入一个值为t或者由args创建的元素。返回新添加元素的迭代器。

  • c.insert(p, n, t);    【在迭代器p指向的元素之前插入n个值为t的元素。返回新添加的第一个元素的迭代器,若n=0,则返回p

   c.insert(p, b, e);    【将迭代器b和e指定的范围内的元素插入到迭代器p之前

   c.insert(p, il);    【il是一个花括号包围的元素值列表,将这些定值插入到迭代器p之前

 

特别的:使用insert的返回值,可以在一个特定的位置反复插入一个值。

while(cin>>word)

  iter = lst.insert(iter, word);

 

  1. 访问元素
  • c.back();    【返回尾元素的引用

   c.front();    【返回收元素的引用

  • c[n];    【也可以直接用下标。适用于string, vector, deque, array

   c.at(n);    【好像和上面差不多,但如果越界会抛出out_of_range异常

 

  1. 删除元素
  • c.pop_back();    【删除c的尾元素,返回void。forward_list不支持

   c.pop_front();    【删除c的首元素,返回void。vector和string不支持

  • c.erase(p);    【删除迭代器p指向的元素,返回被删元素之后的迭代器

   c.erase(b, e);    【删除迭代器b, e中间的元素,返回e后的迭代器

  • c.clear();    【清空c,返回void

 

  1. 改变容器大小
  • c.resize(n);    【如果n比原本的size要大,多出来的值初始化;要小就直接删除
  • c.resize(n, t);    【新添加的元素用t来初始化

 

另外:在对改变了容器的大小以后,迭代器、指针、引用可能会失效。所以应保证每次改变容器的操作之后都正确地重新定位迭代器。且,不要保存end返回的迭代器。

 

六、关于vector与string

  1. vector的增长方式是由系统分配比需求空间更大的内存空间当作备用。
  • c.shrink_to_fit();    【将capacity()减少为与size()相同大小(只是请求,并不保证退还内存。只适用于vector、string、deque
  • c.capacity();    【不重新分配空间的话,c可以保存多少元素   只适用于vector、string
  • c.reserve(n);    【通知容器它应该准备保存多少元素。如果需求大于当前空间,则分配一样或更大的空间;如果小,就什么也不做。

 

  1. 构造string的其他方法:
  • string s(cp, n);    【cp是char型指针,s是cp指向的前n个字符的拷贝
  • string s(s2, pos2);    【s是s2从下标pos2开始的字符的拷贝
  • string s(s2, pos2, len2);    【s是s2从下标pos2开始的len2个字符的拷贝

 

  1. substr:(相当于python的切片
  • s.substr(pos, n);    【从pos开始的n个字符的拷贝,n默认为是从pos到末尾

 

  1. string的其他操作
  • insert、erase可以接受下标的版本
  • insert、assign可以接受char字符数组
  • s.append(args);    【在末尾添加
  • s.replace(pos, n, args);    【在pos后删除n个字符,用args替换,args的长度可以大于n

 

  1. string的搜索(返回指定字符的下标,没有返回npos
  • 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

pos开始查找字符c, pos默认0

s2, pos

pos开始查找字符串s2

cp, pos

pos开始查找cp指向的C风格字符串

cp, pos, n

pos开始查找cp指向的数组前n个字符

循环查找s中所有出现numbers的位置:

while( (pos = s.find_first_of(numbers, pos) ) != string::npos){

  process();

  ++pos;

}

 

  1. compare函数:(s.compare(args);

参数形式:

s2

比较s与s2

pos1, n1, s2

将s中pos2开始的n1个字符与s2比较

pos1, n1, s2, pos2, n2

将s中pos1开始的n1个字符与s2中pos2开始的n2个字符比较

cp

比较s与cp指向的直到空字符

pos1, n1, cp

s中从pos1开始的n1个字符与cp指向直到空字符的比较

pos1, n1, cp, n2

s中从pos1开始的n1个字符与cp指向的n2个字符的比较

 

  1. 数值转换

to_string(val);

val可以是任意算数形式

stoi(s, p, b);

stol(s, p, b);

stoul(s, p, b);

stoll(s, p, b);

stoull(s, p, b);

都是string转换为整型,unsigned、long。

p是size_t型指针,用来保存第一个非数值型字符的下标。

默认0,即不保存。

b是转换用的基数,默认10。

stof(s, p);

stod(s, p);

stold(s, p);

string 转换为float和double,p同上(但是不知道怎么用==

 

七、容器适配器

三个顺序容器适配器:stack、queue、priority_queue

  • 默认情况下,stack和queue是基于deque实现的,priority_queue是基于vector;
  • 但是因为stack只需push_back等,所以除了array、forward_list都可以建造;
  • queue需要push_front等,所以不能用vector;
  • priority_queue需要随机访问,所以能构造与vector、deque,不可list。

 

  1. stack适配器

s.pop();

pop栈顶,但不返回该元素值

s.push(item);

s.emplace();

将item压入栈顶,或者由args建造

s.top();

仅仅返回栈顶元素

用deque等构建了stack以后,就不能用deque的操作了,要用stack自己的操作

 

  1. deque适配器(同priority_queue

q.pop();

返回队列首元素,或priority_queue最高优先级元素,但不删除

q.front();

返回首元素或尾元素,但不删除

q.back();

只适用于queue

q.top();

返回最高优先级元素,只适用于priority_queue

q.push(item);

q.emplace(args);

在queue的末尾或priority_queue中恰当位置创建一个元素,

值为item或由args创建

priority_queue允许给元素建立优先级

 

以上是关于C++ Primer 第九章顺序容器的主要内容,如果未能解决你的问题,请参考以下文章

C++Primer 第九章

第九章 顺序容器

C Primer Plus(第六版)第九章 编程练习答案

第九章: 持有对象

自动化C++第九章实验与作业参考答案

第九章 Servllet工作原理解析