c++ STL

c++ STL


vector如何扩展内存和释放内存

各种容器对比

容器底层数据结构时间复杂度有无序可不可重复其他
array数组随机读改 O(1)无序可重复支持快速随机访问
vector数组随机读改、尾部插入、尾部删除 O(1)、头部插入、头部删除 O(n)无序可重复支持快速随机访问
list双向链表插入、删除 O(1)、随机读改 O(n)无序可重复支持快速增删
deque双端队列头尾插入、头尾删除 O(1)无序可重复一个中央控制器 + 多个缓冲区,支持首尾快速增删,支持随机访问
stackdeque / list顶部插入、顶部删除 O(1)无序可重复deque 或 list 封闭头端开口,不用 vector 的原因应该是容量大小有限制,扩容耗时
queuedeque / list尾部插入、头部删除 O(1)无序可重复deque 或 list 封闭头端开口,不用 vector 的原因应该是容量大小有限制,扩容耗时
priority_queuevector + max - heap插入、删除 O(log2n)有序可重复vector容器 + heap处理规则
set红黑树插入、删除、查找 O(log2n)有序不可重复
multiset红黑树插入、删除、查找 O(log2n)有序可重复
map红黑树插入、删除、查找 O(log2n)有序不可重复
multimap红黑树插入、删除、查找 O(log2n)有序可重复

STL中的swap函数

  • 除了数组,其他容器在交换后本质上是将内存地址进行了交换,而元素本身在内存中的位置是没有变化
  • swap在交换的时候并不是完全将2个容器的元素互换,而是交换了2个容器内的内存地址。

STL中的哈希表扩容

  • 这里需要知道STL中的swap底层,其实扩容也是vector扩容
    • 创建一个新桶,该桶是原来桶两倍大最接近的质数(判断n是不是质数的方法:用n除2到sqrt(n)范围内的数) ;
    • 将原来桶里的数通过指针的转换,插入到新桶中(注意STL这里做的很精细,没有直接将数据从旧桶遍历拷贝数据插入到新桶,而是通过指针转换两个桶的地址)
    • 通过swap函数将新桶和旧桶交换,销毁新桶

vector删除元素后如何避免当前迭代器会失效

删除时,将当前的迭代器存起来

STL迭代器失效的情况和原因

迭代器失效分三种情况考虑,也是分三种数据结构考虑,分别为数组型,链表型,树型数据结构。

  • 数组型数据结构
    • 该数据结构的元素是分配在连续的内存中
    • insert和erase操作,都会使得删除点和插入点之后的元素挪位置,所以,插入点和删除掉之后的迭代器全部失效,也就是说insert(*iter)(或erase(*iter)),然后在iter++,是没有意义的。
    • 解决方法:erase(*iter)的返回值是下一个有效迭代器的值。 iter = cont.erase(iter);
//不要直接在循环条件中写++iter
for (iter = cont.begin(); iter != cont.end();)
{
   (*it)->doSomething();
   if (shouldDelete(*iter))
      iter = cont.erase(iter);  //erase删除元素,返回下一个迭代器
   else
      ++iter;
}
  • 链表型数据结构

    • 对于list型的数据结构,使用了不连续分配的内存
    • 插入不会使得任何迭代器失效
    • 删除运算使指向删除位置的迭代器失效,但是不会失效其他迭代器.
    • 解决办法两种,erase(*iter)会返回下一个有效迭代器的值,或者erase(iter++).
  • 树形数据结构

    • 使用红黑树来存储数据
    • 插入不会使得任何迭代器失效
    • 删除运算使指向删除位置的迭代器失效,但是不会失效其他迭代器.
    • erase迭代器只是被删元素的迭代器失效,但是返回值为void,所以要采用erase(iter++)的方式删除迭代器。

注意 :经过erase(iter)之后的迭代器完全失效,该迭代器iter不能参与任何运算,包括iter++,*ite

vector的iterator和const_iterator和const iterator

  • 三种的区别
    • iterator,可遍历,可改变所指元素
    • const_iterator,可遍历,不可改变所指元素
    • const iterator,不可遍历,可改变所指元素
  • const_iterator转iterator,iterator不能转const_iterator
    • const_iterator 主要是 在容器被定义成常量、或者非常量容器但不想改变元素值的情况 下使用的,而且容器被定义成常量之后,它返回的迭代器只能是const_iterator
    • 有些容器成员函数只接受iterator作为参数,而不是const_iterator。那么,如果你只有一const_iterator,而你要在它所指向的容器位置上插入新元素呢?
      • const_iterator转iterator
      • 强制转换的函数会报错,只能通过 advance(a, distance(a, b)); 其中,distance用于取得两个迭代器之间的距离,advance用于将一个迭代器移动指定的距离
      • 如果a是iterator,b是const_iterator,distance会报错,可以显式的指明distance调用的模板参数类型,从而避免编译器自己得出它们的类型
typedef deque<int> IntDeque;
typedef IntDeque::iterator iter;
typedef IntDeque::const_iterator ConstIter;
IntDeque d;
ConstIter ci;
Iter i(d.begin());
advance(i,distance<ConstIter>(i,ci)); 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清梦旅人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值