各大容器的特点:
-
可以用下标访问的容器有(既可以插入也可以赋值):vector、deque、map;
特别要注意一下,vector和deque如果没有预先指定大小,是不能用下标法插入元素的!
-
序列式容器才可以在容器初始化的时候制定大小,关联式容器不行;
-
注意,关联容器的迭代器不支持it+n操作,仅支持it++操作。
序列式容器
vector
当需要使用数组的情况下,可以考虑使用vector
特点:
(1) 一个动态分配的数组(当数组空间内存不足时,都会执行: 分配新空间-复制元素-释放原空间);
(2) 当删除元素时,不会释放限制的空间,所以向量容器的容量(capacity)大于向量容器的大小(size);
(3) 对于删除或插入操作,执行效率不高,越靠后插入或删除执行效率越高;
(4) 高效的随机访问的容器。
(5)底层内存空间连续
(6)扩容机制:当旧的存储空间不够时,扩充一个新的空间,空间大小为原来大小的两倍,复制元素到新的空间,并释放旧空间。
底层存储结构
为数组,所以支持O(1)快速随机访问,插入尾部为O(n)
创建vecotr对象
(1) vector v1;
(2) vector v2(10);
基本操作:
v.capacity(); //容器容量
v.size(); //容器大小
v.at(int idx); //用法和[]运算符相同
v.push_back(); //尾部插入
v.pop_back(); //尾部删除
v.front(); //获取头部元素
v.back(); //获取尾部元素
v.begin(); //头元素的迭代器
v.end(); //尾部元素的迭代器
v.insert(pos,elem); //pos是vector的插入元素的位置
v.insert(pos, n, elem) //在位置pos上插入n个元素elem
v.insert(pos, begin, end);
v.erase(pos); //移除pos位置上的元素,返回下一个数据的位置
v.erase(begin, end); //移除[begin, end)区间的数据,返回下一个元素的位置
reverse(pos1, pos2); //将vector中的pos1~pos2的元素逆序存储
deque
特点:
(1) deque(double-ended queue 双端队列);
(2) 具有分段数组、索引数组, 分段数组是存储数据的,索引数组是存储每段数组的首地址;
(3) 向两端插入元素效率较高!
若向两端插入元素,如果两端的分段数组未满,既可插入;如果两端的分段数组已满,
则创建新的分段函数,并把分段数组的首地址存储到deque容器中即可)。
中间插入元素效率较低!
底层存储结构
底层内存空间不一定连续,通过map(非STL中的map)数组中的指针来管理不同的连续空间。
通过建立 map 数组,deque 容器申请的这些分段的连续空间就能实现“整体连续”的效果。换句话说,当 deque 容器需要在头部或尾部增加存储空间时,它会申请一段新的连续空间,同时在 map 数组的开头或结尾添加指向该空间的指针,由此该空间就串接到了 deque 容器的头部或尾部。
创建deque对象
(1) deque d1;
(2) deque d2(10);
基本操作:
(1) 元素访问:
d[i];
d.at[i];
d.front();
d.back();
d.begin();
d.end();
添加元素:
d.push_back();
d.push_front();
d.insert(pos,elem); //pos是vector的插入元素的位置
d.insert(pos, n, elem) //在位置pos上插入n个元素elem
d.insert(pos, begin, end);
删除元素:
d.pop_back();
d.pop_front();
d.erase(pos); //移除pos位置上的元素,返回下一个数据的位置
d.erase(begin, end); //移除[begin, end)区间的数据,返回下一个元素的位置
list
特点:
(1) 双向链表:故可以高效地进行首尾插入删除元素。(2)中间删除元素效率低
底层数据结构
是一个双向链表(每个节点有指向前驱和指向后继的两个指针)。
创建对象:
list L1;
list L2(10);
基本操作:
(1) 元素访问:
lt.front();
lt.back();
lt.begin();
lt.end();
(2) 添加元素:
lt.push_back();
lt.push_front();
lt.insert(pos, elem);
lt.insert(pos, n , elem);
lt.insert(pos, begin, end);
lt.pop_back();
lt.pop_front();
lt.erase(begin, end);
lt.erase(elem);
(3)sort()函数、merge()函数、splice()函数:
sort()函数就是对list中的元素进行排序;
merge()函数的功能是:将两个容器合并,合并成功后会按从小到大的顺序排列;
比如:lt1.merge(lt2); lt1容器中的元素全都合并到容器lt2中。
splice()函数的功能是:可以指定合并位置,但是不能自动排序!
关联式容器
- 特点:
(1) 关联式容器都是有序的,升序排列,自动排序;
(2) 实现的是一个平衡二叉树,每个元素都有一个父节点和两个子节点,
左子树的所有元素都比自己小,右子树的所有元素都比自己大;
set
特点:
构造set集合的主要目的是为了快速检索,去重与排序
(1)使用红黑树实现,其内部元素依据其值自动排序,每个元素值只能出现一次(multiset),不允许重复。
(2)每次插入值的时候,都需要调整红黑树,效率有一定影响。(缺点)
(3)map 和 set 的插入或删除效率比用其他序列容器高,因为对于关联容器来说,不需要做内存拷贝和内存移动。(优点)
总结:由红黑树实现,其内部元素依据其值自动排序,每个元素值只能出现一次,不允许重复,且插入和删除效率比用其他序列容器高。
底层数据结构
红黑树(弱平衡二叉搜索树),但采用二分查找法故搜索高效。
创建对象
set<T> s
set<T, op(比较结构体)> s;
//op为排序规则,默认规则是less< T >(升序排列),或者是greater< T >(降序规则)。- 结构体类型(struct )的set ,使用时必须要重载 ‘<’ 运算符
#include<iostream>
#include<set>
#include<string>
using namespace std;
struct Info
{
string name;
double score;
bool operator < (const Info &a) const // 重载“<”操作符,自定义排序规则
{
//按score由大到小排序。如果要由小到大排序,使用“>”即可。
return a.score < score;
}
};
int main()
{
set<Info> s;
Info info;
//插入三个元素
info.name = "Jack";
info.score = 80;
s.insert(info);
info.name = "Tom";
info.score =