[读书笔记] C++Primer (第5版) 第9章 顺序容器

顺序容器名称支持性能
vector可变大小数组快速随机访问在尾部之外的位置插入或删除元素可能很慢
deque双端队列快速随机访问在头尾位置插入/删除速度很快
list双向链表只支持双向顺序访问任何位置插入/删除速度都很快
forward_list单向链表只支持单向顺序访问任何位置插入/删除都很快
array固定大小数组支持快速随机访问不能添加/删除元素
string与vector相似专门用于保存字符串随机访问快,在尾部插入/删除快

1.特点:

   string和vector保存在连续的内存空间中,所以下标访问很快。但在中间插入/删除会很慢,因为要移动修改位置后面所有的元素。

   list和forward_list是为了令容器任何位置添加/删除都很快,但这两个不提供随机访问,只能遍历整个容器。同时与vector,deque和array相比, 额外的内存开销很大,因为链表的元素需要存储指向下个位置的指针。

   array是一种更安全、更容易使用赋值的数组类型。

   通常vector是最好选择,在中间插入和删除操作过多时,可以考虑使用list或forward_list。

2.迭代器:

   迭代器都有公共的接口。所有迭代器都通过解引用运算符(*)来实现访问元素的操作。(有一个例外是forward_list不支持--,因为是单向链表)

   迭代器范围:由两个迭代器表示。  [begin, end) 左闭右开区间。

   begin指向非空此范围的第一个元素,end指向最后一个元素之后的位置。空范围:begin == end3,

3.容器初始化

   创建容器A使用容器B进行拷贝时:两个容器类型和元素类型必须匹配。

   list<string> A = {"a", "b"};   // 使用列表初始化

   deque<string> B(A);          // 错误,容器类型不匹配

   用传递迭代器来拷贝一个范围时,就不要求容器类型相同了。

   deque<string> C(A.begin(), A.end());     // 正确

   定义array:  array<int, 32>;    // 保存32个int数组

   虽然不能对内置数组进行拷贝或对象赋值,但是array可以。

   其他容器定义:vcector<int> vecA(12, 3);     // 12个int元素,每个的初始值为3

4.赋值:

  • c1 = c2      将c1中的元素替换为c2中元素的拷贝。c1和c2必须类型相同
  • c = {a, b, c}  将c1中的元素替换为初始列表中的元素拷贝(array不适用)
  • swap(c1, c2) 或 c1.swap(c2)  交换c1和c2中的元素。c1和c2必须类型相同。通常比拷贝元素快得多
  • seq.assign(b, e) 将seq中的元素替换为迭代器b到e范围所表示的元素。(b和e不能指向seq中元素) 
  • seq.assign(il) 替换为初始化列表il中的元素
  • seq.assign(n, t) 替换为n个值为t的元素

   assign操作不适用与关联容器和array。由于是旧元素被替换,所以传给assign的迭代器不能指向调用assign的容器。

  swap操作元素本身未交换,只交换两个容器的内部数据结构。除array外,不对任何元素进行拷贝、删除或插入操作。意味着,除string外,指向容器的迭代器、引用和指针,在swap后不会失效。

  例如c1和c2进行swap后,iter迭代器指向c1的第二个元素,swap之后,c1变为c2,iter指向c2的第二个元素。

  swap两个array会真正交换它们的元素,所需时间与元素个数成正比。指针,引用等绑定的元素不变,但是元素的值已经发生了改变。

5.关系运算符:

  除了无需关联容器外的所有容器都支持关系运算符(>、>=、<、<=)。容器类型必须相同才能比较

  比较两个容器其实是元素的逐对比较。元素必须也定义了关系运算符。

*****************************以上操作适用于几乎全部容器(顺序和关联容器),以下为顺序容器专属*****************************

顺序容器与关联容器的区别在于组织元素的方式。

6.顺序容器中添加数据:

   array不支持插入,删除操作。forward_list不支持尾部插入(带back的)。vector和string不支持头部插入(带front的)。

  • push_back:将一个元素追加到容器尾部。 用一个对象初始化容器或将一个对象插入的容器中,实际上放入容器中的是对象值的一个拷贝。容器中的元素与提供值的对象之间没有任何关联。
  • push_front:将一个元素插入容器头部。
  • insert:在特定位置插入。第一个参数为迭代器,在该迭代器前进行插入操作。之后的参数可以为元素,n个元素,初始化列表,两个迭代器表示范围。要拷贝的范围不能指向与目的位置相同的容器。返回值指向插入的新的元素的首元素的迭代器。
  • emplace操作:包括emplce_back、emplace_front、emplace。对应前三种操作。push和insert是将元素拷贝到容器中。而emplace是将参数传递给元素的构造函数,在容器管理的内存中直接构造元素。该函数的形参必须与元素构造函数的形参相匹配。

向一个vector,string或deque插入元素,会使指向容器的迭代器,指针和引用失效。

deque在首尾之外添加数据都需要移动。

vector和string在插入点往后需要移动,而且还有可能对整个容器对象存储空间的重新分配,分配一个新的内存,将旧元素移入。

list和forward_list指向容器的迭代器,引用和指针仍有效。

7.访问数据:

  • front():每个顺序容器都有,包括array。
  • back():除array外的每个顺序容器。
  • c[n]:下标访问,n越界则函数行为未定义。
  • c.at(n):下标访问,n越界抛出out_of_range的异常。

对空的容器使用front或back,就像使用越界的下标一样。一种严重的程序设计错误。

8.删除元素:

  • pop_back():从容器尾部删除一个元素。forward_list不支持。
  • pop_front():从容器头部删除一个元素。vector和string不支持。
  • erase(iter):删除迭代器的元素。被删除元素之后的迭代器。forward_list有特殊版本的erase。
  • erase(iterB, iterE):删除迭代器范围的元素。返回最后一个被删除元素后的迭代器。若iterE本身为尾后迭代器,则返回尾后迭代器。
  • clear():删除所有元素。

被删除的元素,迭代器,引用和指针都失效。

删除deque首尾外的元素,都会使所有迭代器,指针和引用失效。

vector和string删除点之后的位置,迭代器,引用和指针会失效。

list和forward_list指向容器其他位置的迭代器,引用和指针仍有效。

9.forward_list的特殊操作:

  forward_list为单链表结构,就以添加和删除只能对某个元素的后继进行操作。

   forward_list有一个首前迭代器,指向第一个元素。

  • list.before_begin():返回首前迭代器。
  • list.insert_after:相当于insert。但是是在第一形参(迭代器)的后面进行插入的。
  • list.emplace_after:相当于empace,但是是在迭代器后创建。
  • erase_after:删除迭代器之后的元素。

注意:不要保存尾后迭代器!!因为操作容器时,尾后迭代器很大可能失效。

10.改变容器大小:

    resize(n)或resize(n, t):调整容器大小。缩小容器则被删除的元素的迭代器等失效,vector,string和deque进行resize可能导致迭代器等失效。

11.vector对象如何增长:

    vector使用连续的内存存储的,如果增加元素导致内存不够用时,会重新分配一块更大的连续内存,并将旧元素全部挪到新内存。

    vector通常会被分配一个比需求空间大些的内存。

    管理容量的函数:

  • c.capacity():不重新分配内存的话,可以保存多少元素。  适用于vector和string。
  • c.reserve(n):分配能容纳n个元素的内存。                       适用于vector和string。
  • c.shrink_to_fit():将capacity()减少为与size()相等。         适用于vector,string和deque。

    只要没有操作需求超出vector的容量,就不能重新分配内存。

    确保用push_back添加元素操作具有较高的效率。

    向一个size为0的vector中,调用n次push_back插入n个元素,所花时间不能超过n的常数倍。

12.容器适配器:

    除顺序容器外,标准库还定义了三种顺序容器适配器:stack,queue和priority_queue。

    例如stack接收一种顺序容器(除array和forward_list外),并使其操作看起来像stack。

    deque<int> dep;

    stack<int>  s(dep);

    所有适配器要求容器有添加,删除和访问元素的功能。

  • 栈适配器(stack):要求push_back,pop_back和back。所以除array和forward_list都可以。先进后出。
  • 队列适配器(queue):要求back,push_back,front和push_front。所以它可以构造于list和deque之上。  先进先出。定义在queue头文件中。
  • 优先级队列适配器(priority_queue):新加的元素排在优先级比它低的元素之前。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值