1、STL中的容器

STL中的常用容器包括:顺序性容器(vector、deque、list)、关联容器(map、set)、容器适配器(queue、stack),
主要是分为 我们常用到的STL容器有vector、list、deque、map、set
STL中顺序容器类和关联式容器类的主要特征如下:
(1)Vector
1、内部数据结构:连续存储,例如数组。
2、随机访问每个元素,所需要的时间为常量。
3、在末尾增加或删除元素所需要时间与元素数目无关,在中间或开头增加或删除元素所需时间随元素数目呈线性变化。
4、可动态增加或减少元素,内存管理自动完成,但程序员可以使用reserve()成员函数来管理内存。
5、vector的迭代器在内存重新分配时将失效(它所指向的元素在该操作的前后不再相同)。当把超过capacity()-size()个元素的插入vector中时,内存会重新分配,所有的迭代器都将失效;否则,指向当前元素以后的任何元素的迭代器都将失效。
建议:使用vector时,用reserve()成员函数预先分配需要的内存空间,它既可以保护迭代器使之不会失效,又可以提高运行效率。
(2)deque
1、内部数据结构:连续存储或分段连续存储,具体依赖于实现。
2,随机访问每个元素,所需要的时间为常量。
3、在开头和结尾增加元素所需时间与元素数目无关,在中间增加或删除元素所需时间随元素数目呈线性变化。
4、可动态增加或减少元素,内存管理自动完成,不提供用于内存管理的成员函数。
5、增加任何元素都将使deque的迭代器失效。在deque的中间删除元素将使迭代器失效。在deque的头或尾删除元素时,只有指向该元素的迭代器失效。
(3)list
1、内部数据结构:双向环状链表。
2、不能随机访问一个元素。
3、可双向遍历。
4、在开头、末尾和中间任何地方增加或删除元素所需时间都为常数。
5、可动态增加或减少元素,内存管理自动完成。
6、增加任何元素都不会使迭代器失效。删除元素时,除了指向当前被删除元素的迭代器外,其他迭代器都不会失效。
(4)slist
1、内部数据结构:单向链表。
2、不可双向遍历,只能从前向后遍历。
3、其他特性与list相同。
建议:尽量不要使用slist的insert,erase,previous等操作。因为这些操作需要向前遍历,但是slist不能直接向前遍历,所以它会从头开始向后搜索,所需时间与位于当前元素之前的元素个数成正比。slist专门提供了insert_after,earse_after等函数进行优化。但若经常需要向前遍历,建议选用list。
(5)stack
适配器,它可以将任意类型的序列容器转换为一个堆栈,一般使用deque作为支持的序列容器。
元素只能后进先出。
不支持遍历操作。
(6)queue
适配器,它可以将任意类型的序列容器转换为一个队列,一般使用deque作为支持的序列容器。
元素只能先进先出。
不支持遍历操作。
(7)priority_queue
适配器,它可以将任意类型的序列容器转换为一个优先队列,一般使用vector作为底层存储结构。
只能访问第一个元素,不支持遍历操作。
第一个元素始终是优先级最高的元素。
建议:当需要stack、queue或priority_queue这样的数据结构时,直接使用对应的容器类,不要使用deque去做它们类似的工作。
(8)set
1、键和值相等。
2、键唯一。
3、元素默认按升序排列。
4、如果迭代器指向的元素被删除,则该迭代器失效。其他任何增加、删除元素的操作都不会使该迭代器失效。
(9)multiset
键可以不唯一。
其他特点与set相同。
(10)hash_set
与set相比较,它里面的元素不一定是经过排序的,而是按照所用的hash函数分派的,它能提供更快的搜索速度(当然跟hash函数有关)。
其他特点与set相同。
(11)hash_multiset
1、键可以不唯一。
2、其他特点与hash_set相同。
(12)map
1、键唯一。
2、元素默认按键的升序排列。
3、如果迭代器所指向的元素被删除,则该迭代器失效。其他任何增加、删除元素的操作都不会使迭代器失效。
(13)multimap
1、键可以不唯一。
2、塔器特点与map相同。
(14)hash_map
1、与map相比较,它里面的元素不一定是按键值排序的,而是按照所用的hash函数分派的,它能提供更快的搜索速度(当然也与hash函数有关)。
2、其他特点与map相同。
(15)hash_multimap
1、键可以不唯一。
2、其他特点与hash_map相同。

建议:
1>当元素的有序比搜索速度更重要时,应选用set、multiset、map或multimap。否则,选用hash_set,hash_multiset,hash_map或hash_multimap。
2>若经常需要在序列容器的开头或中间增加或删除元素时,应选用list。
3>当容器作为参数被传递时,请采用引用传递方式。否则将调用容器的拷贝构造函数,其开销是难以想象的

在实际使用过程中,到底选择这几种容器中的哪一个,应该根据遵循以下原则:
1、如果需要高效的随机存取,不在乎插入和删除的效率,使用vector;
2、如果需要大量的插入和删除元素,不关心随机存取的效率,使用list;
3、如果需要随机存取,并且关心两端数据的插入和删除效率,使用deque;
4、如果打算存储数据字典,并且要求方便地根据key找到value,一对一的情况使用map,一对多的情况使用multimap;
5、如果打算查找一个元素是否存在于某集合中,唯一存在的情况使用set,不唯一存在的情况使用multiset。

2、Qt自带容器

Qt中的容器和STL中的类似,也分为序列式容器和关联式容器。其中,

序列式容器有:QList,QLinkedList,QVector,QStack,QQueue。对大部分应用程序来说,QList都是一个很好的选择。尽管它在底层被实现为一个array-list,但它为我们提供了非常快速的添加操作,包括在头部添加和在尾部添加。如果你确实需要一个linked-list,可以使用QLinkedList;如果你想确保你的元素占用连续的内存空间,可以使用QVector。而QStack和QQueue是两个提供了LIFO和FIFO语义的方便类。

除了序列式容器,Qt中还提供了关联式容器:QMap,QMultiMap,QHash,QMultiHash,QSet。这些容器中存储的都是key-value对。其中,"Multi"容器又支持一个key可以关联多个value。"Hash"容器通过使用一个hash函数而不是二分搜索提供了更快速的查找操作。

我们将这些容器类的总结在下表中:
QList 这是最通用的一个容器类。它里面存储了给定类型T的一个列表,这个列表可以使用下标来访问。其实,在底层QList被实现为一个数组,
确保基于下标的访问非常快速。可以使用QList::append()和QList::prepend()向链表的两端添加元素,或者使用QList::insert()在链表的中间插入元素。
并且,和其他容器相比,更重要的是,QList在可执行文件中展开的代码量是非常少的,是经过高度优化的。QStringList就继承自QList。
QLinkedList 这个容器类类似于QList,只不过它是使用迭代器来访问,而不是下标。当从中间插入时,它的效率比QList还要高。并且,它有更好的迭代器语义。
即指向QLinkedList中某个元素的迭代器,只有该元素存在就会一直保持有效,而指向QList中某元素的迭代器,在向QList进行任意插入或删除时都会导致
该迭代器失效。
QVector 这个容器类会在一块相邻的内存中存储一个给定类型的值的数组。在一个vector的前端或中间插入是非常慢的,因为这会导致大量现存的元素移动以为新的
元素腾出位置。
QStack 这个容器类继承自QVector,提供了“先入后出”的语义。
QQueue 这个容器类继承自QList,提供了“先入先出”的语义。
QSet 这个容器类提供了不允许有重复值的集合,提供快速的查找效率。
QMap<Key, T> 这个容器类提供了一个字典形式的容器,它会将Key类型的值映射到T类型的value上。通常情况下,每一个key只关联一个值。并且,QMap会按Key的顺序存储
相应的值;所以,如果不关心元素的存储顺序,QHash是一个更好的选择。
QMaultiMap<Key, T> 这个容器类继承自QMap,提供了多值的字典,也就是说,该容器中的一个key可以关联多个值。
QHash<Key, T> 这个容器类的API和QMap几乎一样,但它提供了更快速的查找操作。并且,该类会按任意的顺序存储值。
QMultiHash<Key, T> 这个容器类继承自QHash,提供了多值hash表。

容器是可以嵌套使用的。例如,可以使用QMap<QString, QList>这种类型,其key的类型是QString,值类型是QList。
上面提到的这些容器分别被定义在各自的、名称和容器名一样的头文件中。例如,。

这些容器中存储的值可以是任何能被赋值的数据类型,即该类型必须提供一个默认的构造函数、一个拷贝构造函数、一个赋值运算符。这样的数据类型涵盖了大部分你可以存储的类型,包括基本类型入int和double,指针类型,Qt的数据类型QString,QDate,QTime,但不包括QObject或其子类(QWidget,QDialog,QTimer等等)。如果你尝试构建一个QList类型的变量,编译器就会提示你QWidget类的拷贝构造函数和赋值操作符是被禁用的。如果你想存储这些类的对象,可以存储它们的指针类型,例如QList<QWidget*>。

建议:
1.需要让键值对按照插入顺序排列,不需要频繁读取或只需要头尾读取,需要频繁不定位置插入:QList<QPair<QString,QString>>
2.需要让键值对按照插入顺序排列,需要频繁读取, 不需要频繁不定位置插入或只需要在尾部插入:QVector<QPair<QString,QString>>
3.需要让键值对自动排序,速度要求快:QMap
4.不需要让键值对自动排序,速度最快:QHash
5.不需要频繁读取或只需要头尾读取,需要频繁不定位置插入:QList
6.需要频繁读取, 不需要频繁不定位置插入或只需要在尾部插入:QVector
参考文章:Qt常用数据结构集合

3、其他

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐