C++primer 第九章笔记 初稿

9.1 顺序容器

  1. 性质:容器中元素的顺序与加入的位置相对应,为使用者提供了控制元素存储和访问顺序的能力。
  2. 六大顺序容器

    名称 功能 特点>
    vector 可变大小数组 支持快速随机访问,除尾部外插入、删除较慢
    deque 双端队列 支持快速随机访问,头尾外插入删除较慢
    list 双向列表 支持双向顺序访问,任何位置插入删除很快
    forward_list 单项列表 支持正向顺序访问,任何位置插入删除很快
    array 固定大小数组 支持快速随机访问,不能添加删除
    string 字符串 支持快速随机访问,除尾部外插入、删除较慢
  1. list与forward_list相较有更大的额外内存消耗。
  2. array相比内置数组更为安全。
  3. 标准库运行效率较高,应当优先选择标准库而不是原式数据结构。
  4. 如果程序只要在读取时才会向容器中间插入数据,可以设定一个list缓冲。

9.2顺序容器概览(一般操作)

类型与函数 描述
iterator 迭代器
const_iterator 只读迭代器
size_type 无符号整型,描述容器大小或迭代器位置差
difference_type 带符号整型
value_type 元素类型
reference 元素左值类型,与value_type&相似
const_reference const左值
C c, C c(c2), C c(b,e) 构造函数
C c{a,b,c,d…} 构造函数
C c(n), C c(n,t) 构造函数,n为个数,t为初始值
c1=c2, c1={a,b,c,d,…} 赋值
a.swap(b), swap(a,b) 交换
c.size() 元素个数(不支持forward_list
c.max_size() 容器可保存最多元素个数
c.empty() 确认容器是否为空
c.insert(args) 插入元素
c.emplace(inits) 构造一个元素
c.erase(args) 删除元素
c.clear() 清空容器
reverse_iterator 逆寻址迭代器
const_reverse_iterator 只读逆寻址迭代器
c.rbegin(), c.rend(), c.crbegin(), c.crend 返回逆寻址迭代器

对于C c(b,e)的构造方法,C所声明的容器元素类型,必须与b e的类型相容(不一定一样,除array)。

比较运算符必须要求容器中的元素允许元素运算。

  1. 迭代器有公共的接口,forward_list不支持自减操作。

  2. 对反向迭代器使用自增,等价于正向迭代器递减。

  3. 迭代器初始化与拷贝初始化区别

    list<string> ls;
    vector<const char*> vcc;
    
    list<string> ls2(ls);//正确无疑
    deque<string>ds(ls);//错误,容器种类不同 
    vector<string>vs(vcc)//错误,容器元素类型不同
    forward_list<string>fs(vcc.begin(),vcc.end());//正确 
  4. array
    • 支持容器直接拷贝(内置数组当然不行),但是类型和长度必须都一致。
    • 不支持assign与列表赋值。

9.3 顺序容器操作

  1. 赋值与交换

    • 交换两个容器的元素通常比拷贝元素快,除array不涉及任何元素拷贝、删除、插入,故在常数时间完成。

    • 赋值会导致左值容器的迭代器、引用、指针失效,而交换会导致所有迭代器、引用、指针失效(array,string除外)。

    • assign

      • assign(b,e):b和e不能是调用容器的迭代器。
      • assign(n,t):全部替换,没有部分替换的方法。
    • 交换两个array用线性时间,但是元素值改变的同时迭代器所表示的位置不变。

  2. 添加元素

    • push_back()

      • 不支持forward_list。
      • 本质是添加拷贝。
      • 返回void。
    • push_front

      • 支持list,forward_list,deque。
      • 在最开头插入元素,返回void。
    • insert

      • 对push_front不支持不代表对insert插入开头不支持。

      • 在迭代器指向元素之前插入,且返回第一个插入元素的迭代器。

      • 通过将返回值赋值给原迭代器,可实现在同一位置反复插入元素。

      • 也有返回void版本的insert方法。

    • emplace :直接进行初始化
  3. 访问元素

    • front:返回首元素的引用,通过*(c.begin())也可得到。

    • back:返回尾元素的引用,forward_list无,通过*(c.end()-1)也可得到。

    • at(n):返回下标为n的元素的引用。
  4. 删除元素

    • pop_front, pop_back

      • pop_back不支持forward_list,pop_front不支持vector、string。

      • 分别删除首元素与尾元素,容器不可为空,返回void。

    • erase:

      • 删除单个或范围元素,返回被删除的最后一个元素之后的迭代器。

      • 删除单个尾后迭代器是未定义的,范围包含尾后迭代器是可以的。

    • forward_list

      • 特殊原因:作为单向链表,无法通过简答方法获得元素的前驱,故通过改变给定元素之后的元素来实现。
      • insert_after:返回指向最后一个插入元素的迭代器。

      • emplace_after(p,args):插入元素args,返回指向插入元素的迭代器。

      • erase_after(p):删除p指向位置之后的元素,返回指向被删除元素之后的迭代器。
      • erase_after(b,e):删除[b,e)之间的元素,且返回指向被删除元素之后的迭代器。

      • 在forward_list中,通常会有两个变量,一个记录当前迭代器,一个记录前驱迭代器。

        forward_list<int> fl = {0,1,2,3,4,5,6,7,8,9};
        auto prev=fl.before_begin();
        auto curr=fl.begin();
        while(curr!=fl.end()){
            if (*curr % 2)
                curr = fl.erase_after(prev);
            else
                prev = curr++;
        }
  5. 注意点:一旦涉及到容器的插入删除,不要缓存迭代器(end()),应当每次使用都调用一次。

9.4 vector对象的增长方式

  • capacity:当前容器上限元素个数
  • reserve:给容器分配更大的空间(小于等于当前空间不会报错,但是什么也不做)
  • shrink_to_fit:将上限减少到与size()相匹配的大小。

  • vector重新分配内存时一般上限*2。

9.5 string的额外操作

  1. 构造方法

    • (cp,n)
      cp指向的数组中的,前n个元素的拷贝。如果不传递n,指针所指向的数组必须以 ‘\n’ 结尾!

    • (s2,pos2)
      从string类对象s2的下标pos2开始的拷贝,pos2大于s2.size()为未定义的行为。

    • (s2,pos2,len2)
      从string类对象s2的下标pos2开始len2个字符的拷贝,pos2大于s2.size()为未定义的行为,len2过长不影响正常运行。

    • s.substr(pos,n)
      返回字符串s从pos到pos+n-1的子串的拷贝。

  2. 其他操作

    • 存在基于下标运算的insert、erase、assign方法。

    • append(args):类似于”+”。

    • replace(range,args):range为pos开始len长个字符,或者是一对迭代器。
    • 搜索操作

      • 返回值:string::size_type或string::npos。

      • find(args)
        返回调用对象中第一个匹配s的位置的下标,不存在则返回npos。

      • rfind(args)
        返回调用对象中最后一个匹配s的位置的下标,不存在则返回npos。
      • find_first_of(args)、find_last_of(args)
        返回第一次/最后一次args中任一字符出现的位置。
      • find_first_not_of(args)、find_last_not_of(args)
        返回第一次/最后一次不在args中出现的字符位置。
      • 样例:查找数字字符
        
        #include <iostream>
        
        
        #include <cstring>
        
        using namespace std;
        
        int main(){
            string s="ab2c3d7R4E6";
            string sn="0123456789";
            string::size_type pos=0;
            while((pos=s.find_first_of(sn,pos))!=string::npos){
                cout<<s[pos]<<endl;
                pos++;
            } 
            pos=0;
            while((pos=s.find_first_not_of(sn,pos))!=string::npos){
                cout<<s[pos]<<endl;
                pos++;
            }
        
            return 0;
        } 
    • compare方法:类似于strcmp。

    • 数值转换:一般为sto + 类型首字母 + (s,p,b),p为第一个非数值字符的下标,b为基数默认10。
      string s="a=1";
      int i=stoi(s.substr(s.find_first_of(0123456789)));

9.6 顺序容器适配器

  1. 定义:接受一种已有容器,并使其有接收适配器的操作。

  2. 定义适配器

    • 与容器定义类似。

    • 默认下,stack 和 queue 是基于deque实现的,而priority_queue是基于vector实现的。

    • 通过创建适配器时将命名的顺序容器作为第二个参数,可以重载默认容器类型。

      stack<string, vector<string>>str_stk(svec);
    • 限制

      • 适配器不能构造于array、forward_list之上。
      • queue不能构造于vector之上,priority_queue不能构造于list之上。
      • 适配器不可以调用底层容器专有的方法。
  3. 特征

    • queue:先进先出,即进入队列的对象被放置到对尾。
    • priority_queue:新加入的元素排在优先级比其低的元素之前。

你可能感兴趣的:(C语言)