C++ 顺序容器 笔记整理

顺序容器

顺序容器类型

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

deque 双端队列. 支持快速随机访问. 从头尾位置插入or删除元素很快.

list 双向链表. 只支持双向顺序访问. 在`list中任何位置进行插入or删除操作都比较快.

array 固定大小数组.支持快速随机访问. 不能添加or删除元素.

stringvector 类似. 随机访问快.在尾部插入or删除快.

容器操作

// 构造函数
C c;                // 默认构造函数,构造空容器
C c1(c2);           // 构造c2的拷贝c1
C c(b,e);           // 构造c,将迭代器b和e指定范围内的元素拷贝到c (array不支持)
C c{a,b,c};         // 列表初始化{}

// 赋值与swap
c1=c2;              // 将c1中的元素替换c2中的元素
c1={a,b,c...};      // 将c1中的元素替换为列表中的元素! (array不支持)
a.swap(b);          // 交换a,b的元素
swap(a,b);          // 与a.swap(b)等价

// 大小
c.size();           // c中元素的数目 (不支持 forward_list)
c.max_size();       // c可保存的最大元素数目
c.empty();          // 若c中存储元素,返回false.否则为true

// 添加/删除元素 (不适用于array)
// 注:在不同容器中,这些操作的接口都不同
c.insert(args);     // 将args中的元素拷贝进c
c.emplace(inits);   // 使用inits构造c中的一个元素
c.erase(args);      // 删除args指定元素
c.claer();          // 删除c中所有元素,返回void

// 获取迭代器
c.begin();c.end();  // 返回指向c的首元素和尾元素之后位置的迭代器
c.cbegin();c.cend();// 返回const_iterator

// 关系运算符
== !=               // 所有容器都支持的相等/不等 运算符
<,<=,>,>=           // 关系运算符 (无序关联容器不支持)

// 反向容器的额外成员(不支持forward_list)
reverse_iterator;       // 按逆序寻址元素的迭代器
const_reverse_iterator; // 不能修改元素的逆序迭代器
c.rbegin();c.rend();    // 返回指向c尾元素和首元素之前位置的迭代器
c.cebegin();c.crend();  // 返回const_reverse_iterator

迭代器

  • 迭代器范围由一对迭代器表示.

  • 左闭右开 区间!

    begin 与 end 相等,范围为空

  • 不需要写访问时,应使用 cbegincend

容器定义与初始化

C c; // 默认构造函数.若是一个array,则c中元素按默认方式初始化.否则为空.
C c1(c2); // c1初始为为c2的拷贝.注意! 类型相同(容器类型,元素类型).对于array,大小还必须相同.
C c1=c2; 
C c{a,b,c}; // 初始化为初始化列表中元素的拷贝.
C c={a,b,c};
C c(b,e); // 迭代器初始化.c初始化为b和e指定范围中的元素的拷贝.

/* 只有顺序容器(不包括array)的构造器才能大小参数 */
C seq(n); // seq包含n个元素.这些元素进行了初始化.
C seq(n,t); // 初始化了n个元素.值都为t.

赋值与swap

  • 赋值相关运算会导致指向 左边容器 的内部迭代器,引用和指针失效!
  • swap操作将容器内部内容交换 不会 导致指向容器的迭代器,引用和指针失效.(容器类型为array和string的情况除外)
c1=c2; // c1中的元素替换为c2中的元素.
C={a,b,c}; // array不支持
swap(c1,c2); 
c1.swap(c2);
  • assign操作不适用于关联容器和array! 仅顺序容器!
seq.assign(b,e);    // 迭代器b,e不能指向seq中的元素
// 由于旧元素被替换掉了,传递给assign的不能是调用的assign的容器.
seq.assign(il);     // 替换为初始化列表 il 中的元素
seq.assign(n,t);    // 替换为n个t值的元素
  • 统一使用非成员版本的swap是一个好习惯. swap(a,b);

向顺序容器添加元素

  • 顺序容器与关联容器的不同之处在于 二者组织元素的方式.

  • 这些不同之处直接关系到元素如何 存储,访问,添加,删除

  • 非常重要的一点. 除了 forward_list 其他的顺序容器都是前插!!!

// 这些操作会改变容器的大小.array不支持!
c.push_bacck(t);            // 在c的 尾部 创建一个值为t 或由args创建 的元素.
c.emplace_back(args);   
c.push_front(t);            // 在c的 头部 创建一个值为t 或由args创建 的元素.
c.emplace_front(args);
c.insert(p,t);              // 在迭代器p指向的元素 之前 添加一个元素.
c.emplace(p,args);
c.insert(p,n,t);            // 在p指向的元素 之前 添加 n个 值为t的元素
c.insert(p,b,e);            // 将迭代器b和e指定范围的元素插入到 p指向的元素之前!
c.insert(p,il);             // il是一个花括号包围的 元素值列表 ,将这些值插入到p指向元素之前.
  • forward_list 有自己专有版本的 insertemplace ;

  • forward_list 不支持 push_backemplace_back ;

  • vectorstring 不支持 push_frontemplace_front ;

  • 向一个 vector ,stringdeque 插入元素会使所有指向容器的迭代器,引用,指针失效.

  • vector不支持 push_front .但是 我们可以插入到 begin() 之前!!!

    svec.insert(sevc.begin(),"hello!"); // 相当于push_front()
  • 将元素插入到 vector,deque,string 中的任何位置是合法的, 但很耗时.

  • 使用 insert 的返回值,可以容器中的特定一个位置反复的插入元素:

    list<stirng> lst;
    auto iter = lst.begin();
    while(cin>>word)
    iter = lst.insert(iter,word);   //等价与 push_front
  • emplace 函数是在容器中 直接构造 元素.传递给 emplace 函数的参数必须与 元素类型的构造函数 相匹配.

访问元素

c.back();           // 返回c中尾元素的引用;
c.front();          // 返回c中头元素的引用;
c[n];               // 返回下标为n的元素的引用.n是一个无符号整数
c.at(n);            // 返回下标为n的元素的引用. 若越界!会抛出一个 out_of_range的异常
  • at下标操作 只适用于 string vector deque array

  • back 不适用于 forward_list

  • 访问成员函数返回的是 引用

    若容器是一个 const 对象,则返回的是 const 的引用;

    否则,普通引用,可用来改变元素的值;

  • 确保下标访问合法,可以使用 at 成员函数

  • *iter 解引用迭代器也可以访问元素

删除元素

  • 删除元素会改变容器大小,不适用于 array
// 删除元素会改变容器大小,不适用于 array
c.pop_back();           // 删除c中尾元素,返回void
c.pop_front();          // 删除c中首元素,返回void
c.erase(p);             // 删除迭代器p指向的元素,返回一个指向被删除元素 之后 的迭代器!!!
c.erase(b,e);           // 删除b和e所指定范围的元素,返回一个指向最后一个被删除元素 之后 的迭代器!!!
c.clear();              // 删除c中所有元素,返回void
  • forward_list 有特殊版本的 erase

  • forward_list 不支持 pop_back() ;

  • vectorstring 不支持 pop_front() ;

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

  • 指向vectorstring删除点之后 的迭代器,引用,指针都会失效.

  • 删除元素的成员函数并不会检查其参数! 在删除元素之前,请确保它们存在

  • pop_frontpop_back 成员函数返回void,若需要弹出的值! 必须在执行弹出操作前保存它!!!

    使用 front() / back()

  • erase 函数返回的是 指向删除的 最后一个元素之后 位置的迭代器

特殊的 forwartd_list 操作

  • 为什么 forward_list 需要特殊版本的添加和删除操作呢?

    对于单链表来说.添加或删除一个元素.它前面的元素内容也会发生变化.

    为了删除或添加一个元素.必须访问到它的前驱元素.

    在一个forward_list中添加or删除元素的操作都是通过改变 给定元素之后的元素来完成的

  • 首前 迭代器: before_begin

  • forward_list 在添删元素之前,我们必须关注两个迭代器! 指向我们要处理的元素 and 指向其前驱

lst.before_begin();         // 返回指向链表首元素之前 不存在元素 的迭代器,不能解引用!
lst.cbefore_begin();
list.insert_after(p,t);     // 在迭代器p之后 的位置插入元素,t是一个对象!!!
list.insert_after(p,n,t);   // n 是数量
list.insert_after(p,b,e);   // b,e表示范围的一对迭代器
list.insert_after(p,il);    // il是一个花括号列表.
                            // 返回 一个指向最后一个插入的元素之后的迭代器
emplace_after(p,args);      // 使用args在p指定位置之后 创建一个元素.返回一个指向这个新元素的迭代器!
lst.erase_after(p);         // 删除p指向位置之后的元素!
lst.erase_after(b,e);       // 删除从b之后(不包含b)到e之间的元素!
                            // 返回 一个指向被删元素之后元素的迭代器!

改变容器大小

// resize 来增大或减小容器.
c.resize(n);        // 调整c的大小为n个元素.
c.resize(n,t);      // 调整c的大小为n.任何 新添加的 元素值为t
  • resize 不支持 array
  • resize 缩小容器,则指向被删除元素的迭代器,引用,指针都会失效!
  • vector stirng deque 进行 resize 可能导致迭代器,指针,引用失效

  • 关于容器大小的操作.

    成员函数size(); // 返回当前容器中元素的个数
    成员函数empty(); // 当size为0时返回真,否则返回假
    成员函数max_size(); // 返回一个大于或等于该类型容器所能容乃的最大元素的值
  • 关系运算符

    比较两个容器实际上是进行元素的逐对比较.

vector 对象是如何增长的

  • 元素必须是连续存储的.如没有新空间容纳元素,容器必须 分配新的内存空间保存已有元素和新元素 将已有元素从旧位置移动到新空间中,然后添加新元素,释放旧空间!!

  • 为了避免上一条代价,采用 减少容器空间重新分配次数的策略 !!! 通常会分配比新空间要求更大的内存空间!

  • 管理容量的成员函数

    // shrink_to_fit 只适用于 vector string deque
    // capacity 和 reserve 只适用于 vector string
    c.shrink_to_fit();    // 请将capacity() 减少为 size() 相同大小
    c.capacity();     // 不重新分配内存空间的话,c可以容纳多少元素
    c.reserve(n);     // 分配至少容纳n个元素的内存空间
  • reserve 并不改变容器中元素的数量,仅影响 vector 预先分配多大的内存空间

  • 只有当需要的内存空间超过当前容量时reserve 调用才会改变 vector 的容量

  • capacity 是指不重新分配内存空间下,可以容纳多少元素; size 是指它已经保存的元素的数目;

  • 每个 vector 实现都可以选择自己内存分配策略,原则: 只有当迫不得已时才会分配新的内存空间

额外的 string 操作

除了顺序容器共同的操作外.string类型还提供了额外的一些操作.如

  • string类与C风格字符数组之间的转换
  • 增加下标替代迭代器的版本
  • 大量函数

构造 string 的其他方法

// n len2 和 pos2 都是无符号值
string s(cp,n);         // s是cp指向的数组中前n个字符的拷贝.此数组至少应该包含n个字符
string s(s2,pos2);      // s是string s2 从下标pos2开始的字符的拷贝
string s(s2,pos2,len2); // s是string s2 从下标pos2开始的len2个字符的拷贝
  • 通常,当从一个 const char* 创建 string 时,指针指向的数组必须是 以空字符串结尾的 ,拷贝操作遇到 空字符 停止!!!
  • 若传递给构造函数一个 计数值 ,数组 不必以空字符结尾.

  • 若未传递 计数值 且 未以空字符结尾.构造函数的行为 未定义

    const char *cp = "hello world!!!";    // 是以空字符为结尾
    char noNULL[] = {'H','i'};            // 没有空字符结尾
    string s1(cp);            // s1=="hello world!!!"
    string s2(noNULL,2);  // s2=="Hi" // 因为有len.

substr 操作!!!

  • substr 返回一个 string 其实原始字符串或部分字符串的拷贝.
s.substr(pos,n);    // 返回一个stirng,包含spos开始的n个字符的拷贝.pos默认为0,n默认为s.size();
// n是大小,长度!!!

改变 string 的其他操作

除了顺序容器的赋值运算符, assign , insert , erase 操作

  • 接受下标版本的 insert和erase版
  • C风格字符串数组的insert和assign
  • append 和 replace 函数
s.insert(pos,args);         // 在pos之前!!! 插入args指定的字符.pos可以是下标or迭代器.
                            // 接受下标的返回一个指向s的引用; 接受迭代器返回指向 第一个插入字符 的迭代器
s.erase(pos,len);           // 删除从pos开始的len个字符.若len被省略,删除从pos开始到结尾,返回s的一个引用
s.assign(args);             // 将s中的字符替代为args指定的字符.返回一个指向s的引用
s.append(args);             // 将args追加到s.返回一个指向s的引用
s.replace(range,args);      // 删除s中范围range内的字符,替换为args指定字符.
                            // range: 1.一个下标和一个长度 2. 一对指向s的迭代器
  • append assign insert replace 函数有多个重载版本
  • 并不是每个函数都支持所有形式的参数

string 搜索操作

  • 搜索操作返回的是一个 string::size_type 值,表示 匹配发生位置的下标
  • 搜索失败,返回的是 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;          // 从s位置pos开始查找字符c.pos默认为0
s2,pos;         // 从s中查找s2字符串
cp,pos;         // 从s中pos位置开始查找 指针cp指向的以空字符结尾的C风格字符串.pos默认为0
cp,pos,n;       // 从s中pos位置开始查找cp指向的数组的前n个字符.pos 和 n 无默认值

compare 函数

  • 标准库string提供一组 compare 函数,这些函数与C标准库的 strcmp 函数相似
  • s.compare 返回0 正数 负数
// s.compare()的几种参数形式
s2;                 // 比较s和s2
pos1,n1,s2;         // 将s中从pos1开始的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字符 比较

数值转换

// string和数值之间的转换
to_string(val);
stoi(s,p,b);            // 返回s的起始子串(整数的内容)数值,b表示转换所用的基数.默认是10;p是size_t指针.
stol(s,p,b);
stoul(s,p,b);
stoll(s,p,b);
stoull(s,p,b);
stof(s,p);              // f返回s的起始子串(表示浮点数内容)的数值.
stod(s,p);
stold(s,p);
  • 若string不能转换为一个数值,这些函数抛出一个 invalid_argument 异常
  • 若 转换得到的数值 无法用任何类型表示,抛出一个 out_of_range 异常

重点!!!

to_string(val); // 将数值转换成 string啊!!!

stoi(s); // 将string 转成 int

容器适配器

  • 除了顺序容器外,标准库还定义了三个 顺序容器适配器
  • stack queue priority_queue 栈 / 队列 / 优先队列(堆)
  • 适配器 是一种机制!使得某种事物的行为看起来像另一个.
// 所有容器适配器 都支持的操作与类型
size_type;              // 一种类型,足以保存当前类型的最大对象的大小
value_type;             // 元素类型
container_type;         // 实现适配器的底层容器类型
A a;                    // 创建一个名为a的适配器
A a(c);                 // 创建一个名为a的适配器,带有容器c的一个拷贝
关系运算符;              // == != < <= > >=
a.empty();              // 若a包含任意元素,返回false.否则 true
a.size();               // 返回a中的元素数目
swap(a,b);              // 交换a b 内容,ab类型相同,包括底层容器的类型
a.swap(b);          
  • 所有的适配器都要求容器具有添加 删除元素的能力
  • 适配器不能构造在array之上,也不能用forward_list来构造适配器

栈适配器

// 栈操作
s.pop();            // 删除栈顶元素,但不返回该元素值!!!
s.push(item);       // 创建一个新元素 压入栈顶
s.emplace(args);
s.top();            // 返回栈顶元素
  • 只能使用适配器操作! 不能使用底层容器类型的操作
  • 栈 默认是基本 deque 实现的,也可以在 listvector 上实现

队列适配器

// queue 和 priority_queue 操作
q.pop();            // 返回queue的首元素 或 priority_queue的最高优先级元素,但不能删除此元素
q.front();          // 返回首元素 or 尾元素,但不能删除此元素
q.back();           // 只适用于 queue! 
q.top();            // 返回最高优先级元素,但不能删除此元素,只适用于 priority_queue
q.push(item);       // 在queue末尾 或 priority_queue中恰当的位置创建一个元素,其值为tiem,或由args构造
q.emplace(args);    
  • queue 默认基于 deque 实现. 也可以用 list vector 实现
  • priority_queue 默认基于 vector 实现. 也可以用 deque 实现
  • priority_queue 允许我们为队列中的元素建立优先级.新加入的元素会排列在所有优先级比它低的已有元素之前!!!
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值