STL各容器对比

STL容器分类:

  •  顺序(序列)容器:vector, list, deque, string,stack( 适配器类), queue( 适配器类), priority queues( 适配器类)
  •  关联容器:set, multiset, map, multimap, bitset,hash_set, hash_map, hash_multiset, hash_multimap

STL容器简介:

 vector

    变长一维数组,连续存放的内存块,有保留内存,堆中分配内存;

    支持[]操作,高效率的随机访问;

    在最后增加元素时,一般不需要分配内存空间,速度快;在中间或开始操作元素时要进行内存拷贝效率低;

    vector高效的原因在于配置了比其所容纳的元素更多的内存,内存重新配置会花很多时间;

    注:需要高效的随即存取,而不在乎插入和删除使用vector

     

list

    双向链表,内存空间上可能是不连续的,无保留内存,堆中分配内存;

    不支持随机存取,开始和结尾元素的访问时间快,其它元素都On);

    在任何位置安插和删除元素速度都比较快,安插和删除操作不会使其他元素的各个pointerreferenceiterator失效;

   注:大量的插入和删除,而不关系随即存取使用list

   

 deque

    双端队列,在堆上分配内存,一个堆保存几个元素,而堆之间使用指针连接;

   即内存空间分布是小片的连续,小片间用链表相连;

   所以deque空间的重新分配要比vector快,重新分配空间后,原有的元素是不需要拷贝的。

    支持[]操作,在首端和末端插入和删除元素比较快,在中部插入和删除则比较慢,像是listvector的结合;

   注:关心插入和删除并关心随即存取折中使用deque

    

set / multiset

    有序集合,使用平衡二叉树存储,按照给定的排序规则(默认按less排序)对set中的数据进行排序;

    set中不允许有重复元素,multiset中运行有重复元素;

    两者不支持直接存取元素的操作;

    因为是自动排序,查找元素速度比较快;

    不能直接改变元素值,否则会打乱原本正确的顺序,必须先下删除旧元素,再插入新的元素。

    

map / multimap

    字典库,一个值映射成另一个值,使用平衡二叉树存储,按照给定的排序规则对map中的key值进行排序;

    map中的key值不允许重复,multimap中的key允许重复;

    key值不能改变, 根据已知的key值查找元素比较快;

   插入和删除操作比较慢。

   

hash_map

    hash_map使用hash表来排列配对,hash表是使用关键字来计算表位置。当这个表的大小合适,并且计算算法合适的情况下,hash表的算法复杂度为O(1)的,但是这是理想的情况下的,如果hash表的关键字计算与表位置存在冲突,那么最坏的复杂度为O(n)。

     选用map还是hash_map,关键是看关键字查询操作次数,以及你所需要保证的是查询总体时间还是单个查询的时间。如果是要很多次操作,要求其整体效率,那么使用hash_map,平均处理时间短。如果是少数次的操作,使用 hash_map可能造成不确定的O(N),那么使用平均处理时间相对较慢、单次处理时间恒定的map,便更好些。

     默认情况下内部数据不排序。


STL容器对比:

  vector deque list set multiset map multimap
名称 向量容器 双向队列容器 列表容器 集合 多重集合 映射 多重映射

内部数

据结构

连续存储的数组形式(一端开口的组)

连续或分段连续存储数组(两端

开口的数组)

双向环状链表 红黑树(平衡检索二叉树) 红黑树 红黑树 红黑树

 特  点

获取元素效率很高,插入和删除的

效率很低

获取元素效率较高,插入和删除的效率较高

获取元素效率很低,插入和删除的效率很高

1.键(关键字)和值(数据)相等(就是模版只有一个参数,键和值合起来)

2.键唯一

3.元素默认按升序排列

1.键和值相等

2.键可以不唯一

3.元素默认按升序排列

1.键和值分开(模版有两个参数,前面是键后面是值)

2.键唯一

3.元素默认按键的升序排列


1.键和值分开

2.键可以不唯一

3.元素默认按键的升序排列

头文件 #include <vector> #include <deque> #include <list> #include <set> #include <set> #include <map> #include <map>
操作元素的方式 下标运算符:[0](可以用迭代器,但插入删除操作时会失效)

下标运算符或迭代器

只能用迭代器(不断用变量值来递推新值,相当于指针),不支持使用下标运算符

迭代器 迭代器 迭代器 迭代器
插入删除操作迭代器是否失效 插入和删除元素都会使迭代器失效 插入任何元素都会使迭代器失效。删除头和尾元素,指向被删除节点迭代器失效,而删除中间元素会使所有迭代器失效 插入,迭代器不会失效。删除,指向被删除节点迭代器失效 插入,迭代器不会失效。删除,指向被删除节点迭代器失效 插入,迭代器不会失效。删除,指向被删除节点迭代器失效 插入,迭代器不会失效。删除,指向被删除节点迭代器失效 插入,迭代器不会失效。删除,指向被删除节点迭代器失效

有关迭代器失效的问题:https://my.oschina.net/myspaceNUAA/blog/55053

顺序容器,在内存中是一块连续的内存,当删除一个元素后,内存中的数据会发生移动,以保证数据的紧凑。所以删除一个数据后,其他数据的地址发生了变化,之前获取的迭代器根据原有的信息就访问不到正确的数据。

1、对于节点式容器(map, list, set)元素的删除,插入操作会导致指向该元素的迭代器失效,其他元素迭代器不受影响。

2、对于顺序式容器(vector)元素的删除、插入操作会导致指向该元素以及后面的元素的迭代器失效。

vector迭代器的几种失效的情况: 
1、当插入(push_back)一个元素后,end操作返回的迭代器肯定失效。
2、当插入(push_back)一个元素后,capacity返回值与没有插入元素之前相比有改变,则需要重新加载整个容器,此时first和end操作返回的迭代器都会失效。
3、当进行删除操作(erase,pop_back)后,指向删除点的迭代器全部失效;指向删除点后面的元素的迭代器也将全部失效。

  deque迭代器的失效情况: 在C++Primer一书中是这样限定的: 
1、在deque容器首部或者尾部插入元素不会使得任何迭代器失效。 
2、在其首部或尾部删除元素则只会使指向被删除元素的迭代器失效。
3、在deque容器的任何其他位置的插入和删除操作将使指向该容器元素的所有迭代器失效。

注意事项:

1. 当对象很大时,建立指针的容器而不是对象的容器

    STL基于拷贝的方式的来工作,任何需要放入STL中的元素,都会被复制。这也好理解,STL工作的容器是在堆内开辟的一块新空间,而我们自己的变量一般存放在函数栈或另一块堆空间中。为了能够完全控制STL自己的元素,为了能在自己的地盘随心干活,这就涉及到复制。而如果复制的对象很大,由复制带来的性能代价也不小,对于大对象的操作,使用指针来代替对象能消除这方面的代价

2.只涉及到指针拷贝操作, 没有额外类的构造函数和赋值构造函数的调用

不可取:

vecttor vt1;

vt1.push_bach(myBigObj);

可取:

vecttor vt2;

vt2.push_bach(new BigObj());

3. 容器销毁前需要自行销毁指针所指向的对象 , 否则就造成了内存泄漏;

4. 使用排序等算法时,需要构造基于对象的比较函数,如果使用默认的比较函数,其结果是基于指针大小的比较,而不是对象的比较

5. 在使用vector的时候,需要有一点注意:尽量少使用erase,因为在发生erase的时候,会发生一次拷贝,vector要保持结构的完整性,会把从操作对象后的每一个成员都进行一次拷贝,并前移一位,但是在最后一个成员发生移动的时候,如果成员是一个非常规类型,会发生析构,那该成员以及该成员的拷贝都将被删除

6. C++ STL 的 vector 容器在 clear() 之后不会释放内存,需要 swap(empty vector),这是有意为之(C++11 里增加了 shrink_to_fit() 函数)。不要记成了所有 STL 容器都需要swap(empty one) 来释放内存。

 事实上其他容器(map/set/list/deque)都只需要 clear() 就能释放内存。

 只有含 reserve()/capacity() 成员函数的容器才需要用 swap 来释放空间,而 C++ 里只有 vector 和 string 这两个符合条件。


参考链接:

https://blog.csdn.net/dinghqalex/article/details/44194783

https://blog.csdn.net/longhuahaha/article/details/8365041

https://www.jianshu.com/p/52a49ee1b481

迭代器失效:https://blog.csdn.net/tian_110/article/details/43190627

容器及算法使用说明:https://blog.csdn.net/column/details/stl123456.html

算法例子使用说明:https://www.cnblogs.com/BeyondAnyTime/archive/2012/05/27/2520532.html

底层原理图:https://blog.csdn.net/fly_yr/article/details/52091891


猜你喜欢

转载自blog.csdn.net/u012864854/article/details/79920133